Compare commits
2 Commits
a3a2ed8c3f
...
c5776739e0
Author | SHA1 | Date |
---|---|---|
Vencislav Atanasov | c5776739e0 | |
Vencislav Atanasov | 66ac808f42 |
|
@ -4,7 +4,6 @@ import { getSpeakerName, isTrackHidden } from './utils.js';
|
|||
import { Fragment, useState } from 'react';
|
||||
import useScheduleTable from '../hooks/useScheduleTable.js';
|
||||
import Event from './Event.jsx';
|
||||
import defaultSpeaker from '../assets/default-speaker.png';
|
||||
import './Schedule.scss';
|
||||
import { langs } from './constants.js';
|
||||
import Speaker from './Speaker.jsx';
|
||||
|
@ -99,13 +98,13 @@ export default function Schedule({
|
|||
<div className="grid members">
|
||||
{speakers.map(speaker => <div key={speaker.id} className="col4 wmember">
|
||||
<a href={'#'.concat(speaker.id)}>
|
||||
<img width="100" height="100" src={defaultSpeaker} alt={getSpeakerName(speaker)} />
|
||||
<img width="100" height="100" src={speaker.picture} alt={getSpeakerName(speaker)} />
|
||||
</a>
|
||||
</div>)}
|
||||
</div>
|
||||
{speakers.map(speaker => <Fragment key={speaker.id}>
|
||||
<div className="speaker" id={'speaker-'.concat(speaker.id)}>
|
||||
<img width="100" height="100" src={defaultSpeaker} alt={getSpeakerName(speaker)}/>
|
||||
<img width="100" height="100" src={speaker.picture} alt={getSpeakerName(speaker)}/>
|
||||
<h3>{getSpeakerName(speaker)}</h3>
|
||||
<div className="icons">
|
||||
{speaker.twitter && <a href={'https://twitter.com/'.concat(speaker.twitter)}>
|
||||
|
|
|
@ -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 && <>
|
||||
<select value={year} onChange={e => setYear(parseInt(e.target.value, 10))}>
|
||||
{conferences.map(conference =>
|
||||
<option key={conference.id} value={getConferenceYear(conference)}>{conference.title}</option>)}
|
||||
<option key={conference.id} value={conference.start_date.getFullYear()}>{conference.title}</option>)}
|
||||
</select>
|
||||
</>}
|
||||
<ScheduleLoader year={year} lang={lang} />
|
||||
|
|
|
@ -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 && <p>Loading conferences...</p>}
|
||||
|
|
|
@ -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 === 'Други';
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB |
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: [{
|
||||
|
|
12
src/utils.js
12
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;
|
||||
|
|
Loading…
Reference in New Issue