UNPKG

@focus-reactive/graphql-content-layer

Version:

[![npm version](https://badge.fury.io/js/%40focus-reactive%2Fgraphql-content-layer.svg)](https://badge.fury.io/js/%40focus-reactive%2Fgraphql-content-layer) # GitNation GraphQL Content Layer

398 lines (336 loc) 9.95 kB
const dayJS = require('dayjs'); const { createSlug, labelTag, contentTypeMap, range, getSocials } = require('./utils'); const { markdownToHtml } = require('./markdown'); const formatEvent = async (event, labelColors, trackName) => { const overlay = label => labelTag({ prefix: 'talk', labelColors, label }); const { extension, speaker, isoDate, __typename, description, title, track, groupLT, lightningTalks = [], additionalLightningTalks = [], ...rest } = event; const contentType = contentTypeMap[`${__typename}`]; const pieceOfSpeakerInfoes = speaker && speaker.pieceOfSpeakerInfoes[0] || {}; const speakerPlace = speaker && `${speaker.company}, ${speaker.country}`; const lightningTalksWithMarkup = await Promise.all([...lightningTalks, ...additionalLightningTalks].map(async e => { const result = await formatEvent(e, labelColors, trackName); return result; })); const clearLightningTalks = await Promise.all(lightningTalksWithMarkup.map(async el => ({ ...el, text: await markdownToHtml(el.text) }))); return { ...rest, ...speaker, eventType: __typename, title, text: description, description, time: isoDate ? dayJS(isoDate).toISOString() : null, dayISO: isoDate ? dayJS(isoDate).set('hour', 0).set('minute', 0).format('YYYY-MM-DDTHH:mm:ss.000[Z]') : null, track: trackName, name: speaker && speaker.name, place: speakerPlace, slug: title ? createSlug({ title }, 'talk') : null, speakerSlug: speaker ? createSlug(speaker || {}, 'user') : null, contentType, isLightning: __typename === 'LightningTalk' || __typename === 'GroupLT', isoDate: isoDate ? dayJS(isoDate).toISOString() : null, speaker: speaker && speaker.name, from: speakerPlace, label: pieceOfSpeakerInfoes.label, tag: pieceOfSpeakerInfoes.label ? overlay(pieceOfSpeakerInfoes.label) : null, lightningTalks: clearLightningTalks.length ? clearLightningTalks : null, ...extension }; }; const groupByTimeFactory = () => { const dayMap = new Map(); const minMaxByDay = new Map(); const dayMapAdd = (iso, track, event) => { const date = iso.split('T')[0]; if (!dayMap.get(date)) { dayMap.set(date, new Map()); } const trackMap = dayMap.get(date); if (!trackMap.get(track.name)) { trackMap.set(track.name, new Map()); } const timeMap = trackMap.get(track.name); if (!timeMap.get(iso)) { timeMap.set(iso, []); } timeMap.get(iso).push(event); }; const minMaxAdd = iso => { const date = iso.split('T')[0]; if (!minMaxByDay.get(date)) { minMaxByDay.set(date, { min: iso, max: iso }); } else { const container = minMaxByDay.get(date); if (iso < container.min) { container.min = iso; } if (iso > container.max) { container.max = iso; } } }; // removes gaps in time interval (e.g. 12-13, 14-15) const normalizeDayMap = () => { for (const [day, trackMap] of dayMap.entries()) { const minMax = minMaxByDay.get(day); const min = dayJS(minMax.min); const max = dayJS(minMax.max); const diffHours = max.diff(min, 'hour'); for (const diff of range(0, diffHours, 1)) { const date = min.add(diff, 'hour').toISOString(); for (const timeMap of trackMap.values()) { if (!timeMap.get(date)) { timeMap.set(date, null); } } } } }; const mapToObject = orderedTracks => { const result = []; for (const [day, trackMap] of dayMap.entries()) { const dayBucket = []; for (const track of orderedTracks) { const timeMap = trackMap.get(track); if (!timeMap) { continue; } const trackBucket = []; const dates = Array.from(timeMap.keys()); dates.sort(); for (const date of dates) { const dateObj = new Date(date); const hour = dateObj.getUTCHours(); const day = dateObj.getUTCDate(); dateObj.setMinutes(59); dateObj.setSeconds(59); const events = timeMap.get(date); events && events.sort((a, b) => a.time > b.time); trackBucket.push({ id: `time-${day}-${hour}-${hour + 1}`, start: date, end: dateObj.toISOString(), list: events }); } dayBucket.push({ track, list: trackBucket }); } result.push({ day, list: dayBucket }); } return result; }; return { groupTrack: (eventList, track) => { for (const event of eventList) { if (!event.time) { continue; } const beginDate = dayJS(event.time); const beginHour = beginDate.set('minute', 0).set('second', 0); const time = beginHour.toISOString(); minMaxAdd(time); dayMapAdd(time, track, event); } }, buildObject: orderedTracks => { normalizeDayMap(); return mapToObject(orderedTracks); } }; }; const formatActivity = async (event, labelColors, trackName) => { const overlay = label => labelTag({ prefix: 'talk', labelColors, label }); const { startDate, description, title, eventType, subactivities = [], tags, speakers, ...rest } = event; const formattedSubactivities = await Promise.all(subactivities.map(async e => formatActivity(e, labelColors, trackName))); const formattedSpeakers = speakers && speakers.map(speaker => ({ ...speaker, socials: getSocials(speaker) })); return { ...rest, title, description, startDate, isoDate: startDate, eventType, text: description, dayISO: startDate ? dayJS(startDate).set('hour', 0).set('minute', 0).format('YYYY-MM-DDTHH:mm:ss.000[Z]') : null, track: trackName, slug: title ? createSlug({ title }, 'talk') : null, isLightning: eventType === 'LightningTalk' || eventType === 'GroupLT', label: tags && tags[0].label, tag: tags ? overlay(tags[0].label) : null, tags, speakers: formattedSpeakers, subactivities: formattedSubactivities }; }; const groupEmsScheduleByTimeFactory = timezone => { const dayMap = new Map(); const minMaxByDay = new Map(); const dayMapAdd = (isoTz, iso, track, event) => { const date = isoTz.split('T')[0]; if (!dayMap.get(date)) { dayMap.set(date, new Map()); } const trackMap = dayMap.get(date); if (!trackMap.get(track.name)) { trackMap.set(track.name, new Map()); } const timeMap = trackMap.get(track.name); if (!timeMap.get(iso)) { timeMap.set(iso, []); } timeMap.get(iso).push(event); }; const minMaxAdd = (isoTz, iso) => { const date = isoTz.split('T')[0]; if (!minMaxByDay.get(date)) { minMaxByDay.set(date, { min: iso, max: iso }); } else { const container = minMaxByDay.get(date); if (iso < container.min) { container.min = iso; } if (iso > container.max) { container.max = iso; } } }; // removes gaps in time interval (e.g. 12-13, 14-15) const normalizeDayMap = () => { for (const [day, trackMap] of dayMap.entries()) { const minMax = minMaxByDay.get(day); const min = dayJS(minMax.min); const max = dayJS(minMax.max); const diffHours = max.diff(min, 'hour'); for (const diff of range(0, diffHours, 1)) { const date = min.add(diff, 'hour').toISOString(); for (const timeMap of trackMap.values()) { if (!timeMap.get(date)) { timeMap.set(date, null); } } } } }; const mapToObject = orderedTracks => { const result = []; for (const [day, trackMap] of dayMap.entries()) { const dayBucket = []; for (const track of orderedTracks) { const timeMap = trackMap.get(track); if (!timeMap) { continue; } const trackBucket = []; const dates = Array.from(timeMap.keys()); dates.sort(); for (const date of dates) { const dateObj = new Date(date); const hour = dateObj.getUTCHours(); const day = dateObj.getUTCDate(); dateObj.setMinutes(59); dateObj.setSeconds(59); const events = timeMap.get(date); events && events.sort((a, b) => a.startDate > b.startDate); trackBucket.push({ id: `time-${day}-${hour}-${hour + 1}`, start: date, end: dateObj.toISOString(), list: events }); } dayBucket.push({ track, list: trackBucket }); } result.push({ day, list: dayBucket }); } result.sort((a, b) => new Date(a.day).getTime() - new Date(b.day).getTime()); return result; }; return { groupTrack: (eventList, track) => { for (const event of eventList) { if (!event.startDate) { continue; } const beginDate = new Date(event.startDate); // hacky fix to put activity into the right chunk and display it properly on schedule page const beginDateTz = new Date(beginDate.toLocaleString('en-US', { timeZone: timezone })); beginDate.setMinutes(0); beginDate.setSeconds(0); const time = beginDate.toISOString(); const timeTz = beginDateTz.toISOString(); minMaxAdd(timeTz, time); dayMapAdd(timeTz, time, track, event); } }, buildObject: orderedTracks => { normalizeDayMap(); return mapToObject(orderedTracks); } }; }; module.exports = { formatEvent, groupByTimeFactory, formatActivity, groupEmsScheduleByTimeFactory };