Last active
January 16, 2018 09:26
-
-
Save JakeGinnivan/7545ca30565e0a7537d702506ed6dee4 to your computer and use it in GitHub Desktop.
NDC London
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { Component } from "react"; | |
import "./App.css"; | |
import { fetchAgenda, talkShape } from "./fetch-agenda"; | |
import { groupBy, formatTime } from "./utils"; | |
import { Talk } from "./components/talk"; | |
class App extends Component { | |
state = { | |
talks: [] | |
}; | |
async componentWillMount() { | |
const talks = await fetchAgenda(); | |
this.setState({ talks }); | |
} | |
render() { | |
const days = groupBy( | |
this.state.talks, | |
talk => talk.day | |
); | |
return ( | |
<div className="App"> | |
{days.map(day => { | |
const { key, values: talks } = day; | |
return ( | |
<React.Fragment> | |
<h1>Day {key}</h1> | |
{groupBy(talks, talk => | |
formatTime(talk.startTime) | |
).map(timeSlot => ( | |
<React.Fragment> | |
<div> | |
{timeSlot.key} | |
</div> | |
{timeSlot.values.map( | |
talk => ( | |
<Talk | |
talk={talk} | |
/> | |
) | |
)} | |
</React.Fragment> | |
))} | |
</React.Fragment> | |
); | |
})} | |
</div> | |
); | |
} | |
} | |
export default App; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as cheerio from 'cheerio' | |
import * as propTypes from 'prop-types' | |
export const timeShape = propTypes.shape({ | |
hour: propTypes.number.isRequired, | |
minutes: propTypes.number.isRequired | |
}) | |
export const talkShape = propTypes.shape({ | |
title: propTypes.string.isRequired, | |
speaker: propTypes.string.isRequired, | |
location: propTypes.string.isRequired, | |
link: propTypes.string.isRequired, | |
tags: propTypes.arrayOf(propTypes.string).isRequired, | |
startTime: timeShape.isRequired, | |
endTime: timeShape.isRequired, | |
day: propTypes.number.isRequired | |
}) | |
export const fetchAgenda = async () => { | |
// return require('./agenda.json') | |
const response = await fetch('https://ndc-london.com/agenda/') | |
const body = await response.text() | |
const talks = [] | |
const $ = cheerio.load(body) | |
$('section.day').map((i, el) => { | |
// prettier-ignore | |
const dayElements = el.childNodes | |
.filter(c => c.type === 'tag')[0] | |
.children | |
.filter(c => c.type === 'tag') | |
for (var index = 0; index < dayElements.length; index += 2) { | |
const slotEl = cheerio(dayElements[index]) | |
const talkSlot = slotEl.text().split(' - ') | |
const startParts = talkSlot[0].split(':') | |
const endParts = talkSlot[1].split(':') | |
const startTime = { | |
hour: Number(startParts[0]), | |
minutes: Number(startParts[1]) | |
} | |
const endTime = { | |
hour: Number(endParts[0]), | |
minutes: Number(endParts[1]) | |
} | |
cheerio(dayElements[index + 1]) | |
.find('.boxed-talk') | |
.each((j, talkEl) => { | |
const $talk = cheerio(talkEl) | |
const tags = talkEl.attribs['data-slugs'].split(',') | |
const link = talkEl.attribs.href | |
const location = $talk.find('.venue').text() | |
const title = $talk.find('h2').text() | |
const speaker = $talk.find('.speaker').text() | |
talks.push({ | |
title, | |
speaker, | |
location, | |
link, | |
tags, | |
startTime, | |
endTime, | |
day: i + 1 | |
}) | |
}) | |
} | |
}) | |
return talks | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const mountDebugger = (Wrap, name) => { | |
return class MountDebugger extends React.Component { | |
componentWillMount() { | |
console.log(name, 'will mount') | |
} | |
componentDidMount() { | |
console.log(name, 'mounted') | |
} | |
componentDidUpdate() { | |
console.log(name, 'did update') | |
} | |
componentWillReceiveProps() { | |
console.log(name, 'will receive props') | |
} | |
componentWillUnmount() { | |
console.log(name, 'will unmount') | |
} | |
componentWillUpdate() { | |
console.log(name, 'will update') | |
} | |
shouldComponentUpdate() { | |
console.log(name, 'should update?') | |
return true | |
} | |
render() { | |
return <Wrap {...this.props} /> | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function formatTime(time) { | |
const minutes = time.minutes.toString() | |
const formattedMinutes = minutes.length === 1 ? `0${minutes}` : minutes | |
return `${time.hour}:${formattedMinutes}` | |
} | |
/** | |
* | |
* @param {array} items | |
* @param {*} selector | |
* @param {*} toString optionally formats the selector result as a string | |
* this is used to work out if the selector value is the same | |
*/ | |
export function groupBy(items, selector, toString = val => val.toString()) { | |
const lookup = {} | |
return items.reduce((acc, val) => { | |
const selectorValue = selector(val) | |
const key = toString(selectorValue) | |
if (lookup[key]) { | |
lookup[key].push(val) | |
} else { | |
lookup[key] = [val] | |
acc.push({ key: selectorValue, values: lookup[key] }) | |
} | |
return acc | |
}, []) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment