Compare commits
No commits in common. "70b1b36852e6b9c0fb0607176f5e405756aa290c" and "b17572da4b1f8b49f60d436f5b3b9b82d6a86440" have entirely different histories.
70b1b36852
...
b17572da4b
|
@ -1,7 +1,7 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import useSchedule from '../hooks/useSchedule.js';
|
import useSchedule from '../hooks/useSchedule.js';
|
||||||
import { getSpeakerName, isTrackHidden } from './utils.js';
|
import { getSpeakerName, isTrackHidden } from './utils.js';
|
||||||
import { Fragment, useState } from 'react';
|
import { Fragment } from 'react';
|
||||||
import useScheduleTable from '../hooks/useScheduleTable.js';
|
import useScheduleTable from '../hooks/useScheduleTable.js';
|
||||||
import Event from './Event.jsx';
|
import Event from './Event.jsx';
|
||||||
import defaultSpeaker from '../assets/default-speaker.png';
|
import defaultSpeaker from '../assets/default-speaker.png';
|
||||||
|
@ -17,7 +17,6 @@ export default function Schedule({
|
||||||
const {
|
const {
|
||||||
speakers,
|
speakers,
|
||||||
tracks,
|
tracks,
|
||||||
eventTypes,
|
|
||||||
halls,
|
halls,
|
||||||
events,
|
events,
|
||||||
slots,
|
slots,
|
||||||
|
@ -26,32 +25,25 @@ export default function Schedule({
|
||||||
isComplete,
|
isComplete,
|
||||||
} = useSchedule(conferenceId);
|
} = useSchedule(conferenceId);
|
||||||
|
|
||||||
const [eventTypeId, setEventTypeId] = useState(0);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
header,
|
header,
|
||||||
rows,
|
rows,
|
||||||
} = useScheduleTable({
|
} = useScheduleTable({
|
||||||
eventTypeId,
|
tracks,
|
||||||
halls,
|
halls,
|
||||||
events,
|
events,
|
||||||
slots,
|
slots,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (<>
|
return (<>
|
||||||
{isComplete && <select value={eventTypeId} onChange={e => setEventTypeId(parseInt(e.target.value, 10))}>
|
|
||||||
<option value={0}>All event types</option>
|
|
||||||
{eventTypes.map(eventType =>
|
|
||||||
<option key={eventType.id} value={eventType.id}>{eventType.name[lang]}</option>)}
|
|
||||||
</select>}
|
|
||||||
{isLoading && <progress value={loadingProgress}/>}
|
{isLoading && <progress value={loadingProgress}/>}
|
||||||
{isComplete && <div className="schedule">
|
{isComplete && <div className="schedule">
|
||||||
<hr/>
|
<hr />
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
{header.map(hall => <th key={hall.id}>{hall.name[lang]}</th>)}
|
{header.map(hall => <th key={hall.id}>{hall.name[lang]}</th>)}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{rows.map(row => <tr key={row.id}>
|
{rows.map(row => <tr key={row.id}>
|
||||||
|
@ -69,7 +61,9 @@ export default function Schedule({
|
||||||
<div className="separator"/>
|
<div className="separator"/>
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{tracks.filter(track => !isTrackHidden(track)).map(track => <tr key={track.id}>
|
{Object.values(tracks).filter(track =>
|
||||||
|
!isTrackHidden(track)
|
||||||
|
).map(track => <tr key={track.id}>
|
||||||
<td className={track.css_class}>{track.name[lang]}</td>
|
<td className={track.css_class}>{track.name[lang]}</td>
|
||||||
</tr>)}
|
</tr>)}
|
||||||
{Object.entries(langs).map(([langId, langName]) => <tr key={langId}>
|
{Object.entries(langs).map(([langId, langName]) => <tr key={langId}>
|
||||||
|
@ -78,7 +72,7 @@ export default function Schedule({
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
<div className="separator" />
|
<div className="separator" />
|
||||||
{events.map(event => <section key={event.id} id={'event-'.concat(event.id)}>
|
{Object.values(events).map(event => <section key={event.id} id={'event-'.concat(event.id)}>
|
||||||
<p>
|
<p>
|
||||||
<strong>{event.title}</strong>
|
<strong>{event.title}</strong>
|
||||||
{event.participant_users && !isTrackHidden(event.track) && <>
|
{event.participant_users && !isTrackHidden(event.track) && <>
|
||||||
|
@ -97,13 +91,13 @@ export default function Schedule({
|
||||||
</section>)}
|
</section>)}
|
||||||
{<>
|
{<>
|
||||||
<div className="grid members">
|
<div className="grid members">
|
||||||
{speakers.map(speaker => <div key={speaker.id} className="col4 wmember">
|
{Object.values(speakers).map(speaker => <div key={speaker.id} className="col4 wmember">
|
||||||
<a href={'#'.concat(speaker.id)}>
|
<a href={'#'.concat(speaker.id)}>
|
||||||
<img width="100" height="100" src={defaultSpeaker} alt={getSpeakerName(speaker)} />
|
<img width="100" height="100" src={defaultSpeaker} alt={getSpeakerName(speaker)} />
|
||||||
</a>
|
</a>
|
||||||
</div>)}
|
</div>)}
|
||||||
</div>
|
</div>
|
||||||
{speakers.map(speaker => <Fragment key={speaker.id}>
|
{Object.values(speakers).map(speaker => <Fragment key={speaker.id}>
|
||||||
<div className="speaker" id={'speaker-'.concat(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={defaultSpeaker} alt={getSpeakerName(speaker)}/>
|
||||||
<h3>{getSpeakerName(speaker)}</h3>
|
<h3>{getSpeakerName(speaker)}</h3>
|
||||||
|
|
|
@ -4,7 +4,7 @@ import useTracks from './useTracks.js';
|
||||||
import useEventTypes from './useEventTypes.js';
|
import useEventTypes from './useEventTypes.js';
|
||||||
import useHalls from './useHalls.js';
|
import useHalls from './useHalls.js';
|
||||||
import useSlots from './useSlots.js';
|
import useSlots from './useSlots.js';
|
||||||
import { calculateProgress, normalizeResponse } from '../utils.js';
|
import { addIdAndRelations, calculateProgress } from '../utils.js';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
export default function useSchedule(conferenceId) {
|
export default function useSchedule(conferenceId) {
|
||||||
|
@ -14,7 +14,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: speakersValidating,
|
isValidating: speakersValidating,
|
||||||
} = useSpeakers(conferenceId);
|
} = useSpeakers(conferenceId);
|
||||||
|
|
||||||
const speakers = useMemo(() => normalizeResponse(speakersResponse), [speakersResponse]);
|
const speakers = useMemo(() => addIdAndRelations(speakersResponse || []), [speakersResponse]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: tracksResponse,
|
data: tracksResponse,
|
||||||
|
@ -22,7 +22,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: tracksValidating,
|
isValidating: tracksValidating,
|
||||||
} = useTracks(conferenceId);
|
} = useTracks(conferenceId);
|
||||||
|
|
||||||
const tracks = useMemo(() => normalizeResponse(tracksResponse), [tracksResponse]);
|
const tracks = useMemo(() => addIdAndRelations(tracksResponse || []), [tracksResponse]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: eventTypesResponse,
|
data: eventTypesResponse,
|
||||||
|
@ -30,7 +30,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: eventTypesValidating,
|
isValidating: eventTypesValidating,
|
||||||
} = useEventTypes(conferenceId);
|
} = useEventTypes(conferenceId);
|
||||||
|
|
||||||
const eventTypes = useMemo(() => normalizeResponse(eventTypesResponse), [eventTypesResponse]);
|
const eventTypes = useMemo(() => addIdAndRelations(eventTypesResponse || []), [eventTypesResponse]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: hallsResponse,
|
data: hallsResponse,
|
||||||
|
@ -38,7 +38,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: hallsValidating,
|
isValidating: hallsValidating,
|
||||||
} = useHalls(conferenceId);
|
} = useHalls(conferenceId);
|
||||||
|
|
||||||
const halls = useMemo(() => normalizeResponse(hallsResponse), [hallsResponse]);
|
const halls = useMemo(() => addIdAndRelations(hallsResponse || []), [hallsResponse]);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: eventsResponse,
|
data: eventsResponse,
|
||||||
|
@ -46,7 +46,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: eventsValidating,
|
isValidating: eventsValidating,
|
||||||
} = useEvents(conferenceId);
|
} = useEvents(conferenceId);
|
||||||
|
|
||||||
const events = useMemo(() => normalizeResponse(eventsResponse, [
|
const events = useMemo(() => addIdAndRelations(eventsResponse || [], [
|
||||||
['event_type', eventTypes, 'event_type_id'],
|
['event_type', eventTypes, 'event_type_id'],
|
||||||
['track', tracks, 'track_id'],
|
['track', tracks, 'track_id'],
|
||||||
['participant_users', speakers, 'participant_user_ids'],
|
['participant_users', speakers, 'participant_user_ids'],
|
||||||
|
@ -58,7 +58,7 @@ export default function useSchedule(conferenceId) {
|
||||||
isValidating: slotsValidating,
|
isValidating: slotsValidating,
|
||||||
} = useSlots(conferenceId);
|
} = useSlots(conferenceId);
|
||||||
|
|
||||||
const slots = useMemo(() => normalizeResponse(slotsResponse, [
|
const slots = useMemo(() => addIdAndRelations(slotsResponse || [], [
|
||||||
['hall', halls, 'hall_id'],
|
['hall', halls, 'hall_id'],
|
||||||
['event', events, 'event_id'],
|
['event', events, 'event_id'],
|
||||||
]), [slotsResponse, halls, events]);
|
]), [slotsResponse, halls, events]);
|
||||||
|
|
|
@ -1,17 +1,10 @@
|
||||||
import { useMemo } from 'react';
|
|
||||||
|
|
||||||
export default function useScheduleTable({
|
export default function useScheduleTable({
|
||||||
eventTypeId,
|
|
||||||
halls = {},
|
|
||||||
events = {},
|
events = {},
|
||||||
slots = {},
|
halls = {},
|
||||||
}) {
|
}) {
|
||||||
const filteredEvents = useMemo(() => events.filter(event => eventTypeId > 0 ? event.event_type_id === eventTypeId : true), [eventTypeId, events]);
|
const header = Object.values(halls);
|
||||||
const filteredEventIds = useMemo(() => filteredEvents.map(event => event.id), [filteredEvents]);
|
|
||||||
const filteredHallIds = useMemo(() => new Set(slots.filter(slot => filteredEventIds.includes(slot.event_id)).map(slot => slot.hall_id)), [filteredEventIds, slots]);
|
|
||||||
const header = useMemo(() => halls.filter(hall => filteredHallIds.has(hall.id)), [filteredHallIds, halls]);
|
|
||||||
|
|
||||||
const rows = filteredEvents.map(event => ({
|
const rows = Object.values(events).map(event => ({
|
||||||
id: event.id,
|
id: event.id,
|
||||||
cells: [{
|
cells: [{
|
||||||
id: 1,
|
id: 1,
|
||||||
|
|
23
src/utils.js
23
src/utils.js
|
@ -42,19 +42,14 @@ export function calculateProgress(...elements) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export const normalizeResponse = (items = [], relations = []) =>
|
export const addIdAndRelations = (items, relations = []) =>
|
||||||
Object.entries(items).map(([id, item]) =>
|
Object.fromEntries(Object.entries(items).map(([id, item]) =>
|
||||||
({
|
([id, {
|
||||||
id: parseInt(id, 10),
|
id: parseInt(id, 10),
|
||||||
...item,
|
...item,
|
||||||
...Object.fromEntries(relations.map(([field, collection, idField]) => {
|
...Object.fromEntries(relations.map(([field, collection, idField]) => ([
|
||||||
const key = item[idField];
|
field,
|
||||||
const fn = Array.isArray(key) ? 'filter' : 'find';
|
Array.isArray(item[idField]) ? item[idField].map(id => collection[id]) : collection[item[idField]],
|
||||||
|
]))),
|
||||||
return [
|
}])
|
||||||
field,
|
));
|
||||||
collection[fn](item => item.id === key),
|
|
||||||
];
|
|
||||||
})),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
Loading…
Reference in New Issue