From 66ac808f420025836db9ebbfdccfc62d5882f403 Mon Sep 17 00:00:00 2001 From: Vencislav Atanasov Date: Tue, 24 Sep 2024 01:36:53 +0300 Subject: [PATCH] Parse dates in the API response, simplify sorting --- src/Schedule/ScheduleChooser.jsx | 7 +++---- src/Schedule/ScheduleLoader.jsx | 6 ++---- src/Schedule/utils.js | 2 -- src/hooks/useConferences.js | 21 ++++++++++++++++++++- src/hooks/useSchedule.js | 9 +++++++-- src/hooks/useScheduleTable.js | 13 +++++++++++-- src/utils.js | 12 +++++++----- 7 files changed, 50 insertions(+), 20 deletions(-) diff --git a/src/Schedule/ScheduleChooser.jsx b/src/Schedule/ScheduleChooser.jsx index 21dd99e..ea102e9 100644 --- a/src/Schedule/ScheduleChooser.jsx +++ b/src/Schedule/ScheduleChooser.jsx @@ -1,9 +1,8 @@ import ScheduleLoader from './ScheduleLoader.jsx'; import { langs } from './constants.js'; import { useMemo, useState } from 'react'; -import { dateSorter } from '../utils.js'; +import { sorter } from '../utils.js'; import useConferences from '../hooks/useConferences.js'; -import { getConferenceYear } from './utils.js'; export default function ScheduleChooser() { const { @@ -12,7 +11,7 @@ export default function ScheduleChooser() { isLoading, } = useConferences(); - const conferences = useMemo(() => Array.isArray(data) ? data.sort(dateSorter('start_date')) : data, [data]); + const conferences = useMemo(() => Array.isArray(data) ? data.sort(sorter('start_date')) : data, [data]); const [ year, setYear ] = useState(2023); const [ lang, setLang ] = useState('bg'); @@ -29,7 +28,7 @@ export default function ScheduleChooser() { {conferences && <> } diff --git a/src/Schedule/ScheduleLoader.jsx b/src/Schedule/ScheduleLoader.jsx index 2384dec..1248af0 100644 --- a/src/Schedule/ScheduleLoader.jsx +++ b/src/Schedule/ScheduleLoader.jsx @@ -13,10 +13,8 @@ export default function ScheduleLoader({ isLoading, } = useConferences(); - const conferenceId = useMemo(() => data && data.filter(conference => { - const dt = new Date(Date.parse(conference.start_date)); - return dt.getFullYear() === year; - })?.[0]?.id, [data, year]); + const conferenceId = useMemo(() => data && data.filter(conference => + conference.start_date.getFullYear() === year)?.[0]?.id, [data, year]); return (<> {isLoading &&

Loading conferences...

} diff --git a/src/Schedule/utils.js b/src/Schedule/utils.js index 4c6f3ab..a1a7d75 100644 --- a/src/Schedule/utils.js +++ b/src/Schedule/utils.js @@ -1,5 +1,3 @@ -export const getConferenceYear = conference => (new Date(conference.start_date)).getFullYear(); - export const getSpeakerName = speaker => speaker.first_name.concat(' ').concat(speaker.last_name); export const isTrackHidden = track => track?.name?.en === 'Other' || track?.name?.bg === 'Други'; diff --git a/src/hooks/useConferences.js b/src/hooks/useConferences.js index 6a8edda..965c0a1 100644 --- a/src/hooks/useConferences.js +++ b/src/hooks/useConferences.js @@ -1,5 +1,24 @@ import useCfpRequest from './useCfpRequest.js'; +import { useMemo } from 'react'; +import { parseDateFields } from '../utils.js'; export default function useConferences() { - return useCfpRequest('.json'); + const { + data: conferences, + ...restOfRequest + } = useCfpRequest('.json'); + + const parsedConferences = useMemo(() => (conferences ?? []).map(conference => + parseDateFields(conference, [ + 'start_date', + 'end_date', + 'created_at', + 'updated_at', + ]) + ), [conferences]); + + return { + data: parsedConferences, + ...restOfRequest, + }; } diff --git a/src/hooks/useSchedule.js b/src/hooks/useSchedule.js index 24a2893..025c00d 100644 --- a/src/hooks/useSchedule.js +++ b/src/hooks/useSchedule.js @@ -4,7 +4,7 @@ import useTracks from './useTracks.js'; import useEventTypes from './useEventTypes.js'; import useHalls from './useHalls.js'; import useSlots from './useSlots.js'; -import { calculateProgress, normalizeResponse } from '../utils.js'; +import { calculateProgress, normalizeResponse, parseDateFields } from '../utils.js'; import { useMemo } from 'react'; export default function useSchedule(conferenceId) { @@ -61,7 +61,12 @@ export default function useSchedule(conferenceId) { const slots = useMemo(() => normalizeResponse(slotsResponse, [ ['hall', halls, 'hall_id'], ['event', events, 'event_id'], - ]), [slotsResponse, halls, events]); + ]).map(slot => + parseDateFields(slot, [ + 'starts_at', + 'ends_at', + ]) + ), [slotsResponse, halls, events]); const { isStarted: isLoading, diff --git a/src/hooks/useScheduleTable.js b/src/hooks/useScheduleTable.js index 3baf81b..9811ee7 100644 --- a/src/hooks/useScheduleTable.js +++ b/src/hooks/useScheduleTable.js @@ -1,4 +1,5 @@ import { useMemo } from 'react'; +import { sorter } from '../utils.js'; export default function useScheduleTable({ eventTypeId, @@ -9,10 +10,18 @@ export default function useScheduleTable({ return useMemo(() => { const filteredEvents = events.filter(event => eventTypeId > 0 ? event.event_type_id === eventTypeId : true); const filteredEventIds = filteredEvents.map(event => event.id); - const filteredSlots = slots.filter(slot => filteredEventIds.includes(slot.event_id)); + const filteredSlots = slots.sort(sorter('starts_at')).filter(slot => filteredEventIds.includes(slot.event_id)); + const days = Array.from(new Set(filteredSlots.map(slot => + slot.starts_at.setHours(0, 0, 0, 0) + ))).map(ts => new Date(ts)); const filteredHallIds = new Set(filteredSlots.map(slot => slot.hall_id)); - const header = halls.filter(hall => filteredHallIds.has(hall.id)); + const filteredHalls = halls.filter(hall => filteredHallIds.has(hall.id)); + const hallSlots = Object.fromEntries(filteredHalls.map(hall => [ + hall.id, + filteredSlots.filter(slot => slot.hall_id === hall.id), + ])); + const header = filteredHalls; const rows = filteredEvents.map(event => ({ id: event.id, cells: [{ diff --git a/src/utils.js b/src/utils.js index 46eea78..2ce61b5 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,13 +1,15 @@ -function sorter(a, b, fieldFn) { - const fieldA = fieldFn(a); - const fieldB = fieldFn(b); +export const sorter = field => (a, b) => { + const fieldA = a[field]; + const fieldB = b[field]; return fieldA === fieldB ? 0 : ( fieldA < fieldB ? -1 : 1 ); -} +}; -export const dateSorter = key => (a, b) => sorter(a, b, item => Date.parse(item[key])); +export const parseDateFields = (item, dateFields) => Object.fromEntries(Object.entries(item).map(([key, value]) => + [key, dateFields.includes(key) ? new Date(value) : value] +)); export function calculateProgress(...elements) { const totalCount = elements.length;