Skip to content

Instantly share code, notes, and snippets.

@JakeGinnivan
Last active January 16, 2018 09:26
Show Gist options
  • Save JakeGinnivan/7545ca30565e0a7537d702506ed6dee4 to your computer and use it in GitHub Desktop.
Save JakeGinnivan/7545ca30565e0a7537d702506ed6dee4 to your computer and use it in GitHub Desktop.
NDC London
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;
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
}
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} />
}
}
}
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