Compare commits

..

No commits in common. "f6c71b98977950683473cfa9dcbac8c600bd06d2" and "4774dcda11d2dd224788c4f36764a29d597d47d4" have entirely different histories.

7 changed files with 86 additions and 142 deletions

View File

@ -1,18 +1,11 @@
import { isTrackHidden } from './utils.js'; import PropTypes from 'prop-types';
import Speaker from './Speaker.jsx';
import FeedbackLink from './FeedbackLink.jsx';
export default function Event(event) { export default function Event({
return (<> title,
<a href={'#lecture-'.concat(event.id)}>{event.title}</a> }) {
<br /> return (<strong>{title}</strong>);
{event.participant_users && !isTrackHidden(event.track) && <>
{event.participant_users.map(speaker => speaker && <Speaker key={speaker.id} {...speaker} />)}
</>}
<p>
<i>
<FeedbackLink {...event} />
</i>
</p>
</>);
} }
Event.propTypes = {
title: PropTypes.string.isRequired,
};

View File

@ -1,3 +0,0 @@
export default function FeedbackLink(event) {
return (<a href={event.feedback_url}>Submit feedback</a>);
}

View File

@ -7,8 +7,6 @@ import Event from './Event.jsx';
import defaultSpeaker from '../assets/default-speaker.png'; import defaultSpeaker from '../assets/default-speaker.png';
import './Schedule.scss'; import './Schedule.scss';
import { langs } from './constants.js'; import { langs } from './constants.js';
import Speaker from './Speaker.jsx';
import FeedbackLink from './FeedbackLink.jsx';
export default function Schedule({ export default function Schedule({
conferenceId, conferenceId,
@ -22,7 +20,6 @@ export default function Schedule({
slots, slots,
isLoading, isLoading,
loadingProgress, loadingProgress,
isComplete,
} = useSchedule(conferenceId); } = useSchedule(conferenceId);
const { const {
@ -30,7 +27,6 @@ export default function Schedule({
rows, rows,
} = useScheduleTable({ } = useScheduleTable({
events, events,
tracks,
halls, halls,
slots, slots,
lang, lang,
@ -38,46 +34,57 @@ export default function Schedule({
return (<> return (<>
{isLoading && <progress value={loadingProgress}/>} {isLoading && <progress value={loadingProgress}/>}
{isComplete && <div className="schedule"> <div className="schedule">
<hr /> <hr />
<table> {header && rows && <>
<thead> <table>
<tr> <thead>
{header.map(hall => <th key={hall.id}>{hall.name}</th>)} <tr>
</tr> {header.map(hall => <th key={hall.id}>{hall.name}</th>)}
</thead> </tr>
<tbody> </thead>
{rows.map(row => <tr key={row.id}> <tbody>
{row.cells.map(cell => <td key={cell.id} {...cell.attributes}> {rows.map(row => <tr key={row.id}>
<Event {...cell.event} /> {row.cells.map(cell => <td key={cell.id} {...cell.attributes}>
</td>)} <Event {...cell.event} />
</tr>)} </td>)}
</tbody> </tr>)}
<tfoot> </tbody>
<tr> <tfoot>
{header.map(hall => <th key={hall.id}>{hall.name}</th>)} <tr>
</tr> {header.map(hall => <th key={hall.id}>{hall.name}</th>)}
</tfoot> </tr>
</table> </tfoot>
<div className="separator"/> </table>
<table> <div className="separator"/>
<tbody> </>}
{Object.entries(tracks).filter(([, track]) => {tracks && <>
!isTrackHidden(track) <table>
).map(([trackId, track]) => <tr key={trackId}> <tbody>
<td className={track.css_class}>{track.name[lang]}</td> {Object.entries(tracks).filter(([, track]) =>
</tr>)} !isTrackHidden(track)
{Object.entries(langs).map(([code, name]) => <tr key={code}> ).map(([trackId, track]) => <tr key={trackId}>
<td className={'schedule-'.concat(code)}>{name}</td> <td className={track.css_class}>{track.name[lang]}</td>
</tr>)} </tr>)}
</tbody> {Object.entries(langs).map(([code, name]) => <tr key={code}>
</table> <td className={'schedule-'.concat(code)}>{name}</td>
<div className="separator" /> </tr>)}
{Object.entries(events).map(([eventId, event]) => <section key={eventId} id={'lecture-'.concat(eventId)}> </tbody>
</table>
<div className="separator" />
</>}
{events && tracks && Object.entries(events).map(([eventId, event]) => <section key={eventId} id={'lecture-'.concat(eventId)}>
<p> <p>
<strong>{event.title}</strong> <strong>{event.title}</strong>
{event.participant_users && !isTrackHidden(event.track) && <> {event.participant_user_ids && !isTrackHidden(tracks[event.track_id]) && speakers && <>
({event.participant_users.map(speaker => speaker && <Speaker key={speaker.id} {...speaker} />)}) ({event.participant_user_ids.map(speakerId => speakers[speakerId] && <Fragment key={speakerId}>
<a key={speakerId} href={'#'.concat(getSpeakerName(speakers[speakerId]))}>
{getSpeakerName(speakers[speakerId])}
</a>
{speakers[speakerId].organisation && <>
/&#8288;{speakers[speakerId].organisation}&#8288;/
</>}
</Fragment>).filter(item => !!item)})
</>} </>}
</p> </p>
{event.abstract && <p> {event.abstract && <p>
@ -85,12 +92,12 @@ export default function Schedule({
</p>} </p>}
<p className="feedback"> <p className="feedback">
<strong> <strong>
<FeedbackLink {...event} /> <a href={event.feedback_url}>Submit feedback</a>
</strong> </strong>
</p> </p>
<div className="separator" /> <div className="separator" />
</section>)} </section>)}
{<> {speakers && <>
<div className="grid members"> <div className="grid members">
{Object.entries(speakers).map(([speakerId, speaker]) => <div key={speakerId} className="col4 wmember"> {Object.entries(speakers).map(([speakerId, speaker]) => <div key={speakerId} className="col4 wmember">
<a href={'#'.concat(getSpeakerName(speaker))}> <a href={'#'.concat(getSpeakerName(speaker))}>
@ -115,7 +122,7 @@ export default function Schedule({
<div className="separator" /> <div className="separator" />
</Fragment>)} </Fragment>)}
</>} </>}
</div>} </div>
</>); </>);
} }

View File

@ -1,15 +0,0 @@
import { getSpeakerName } from './utils.js';
import PropTypes from 'prop-types';
export default function Speaker(speaker) {
return (<>
<a href={'#'.concat(getSpeakerName(speaker))}>{getSpeakerName(speaker)}</a>
{speaker.organisation && <>/&#8288;{speaker.organisation}&#8288;/</>}
</>);
}
Speaker.propTypes = {
first_name: PropTypes.string.isRequired,
last_name: PropTypes.string.isRequired,
organisation: PropTypes.string,
};

View File

@ -4,65 +4,45 @@ 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 { addIdAndRelations, calculateProgress } from '../utils.js'; import { calculateProgress } from '../utils.js';
import { useMemo } from 'react';
export default function useSchedule(conferenceId) { export default function useSchedule(conferenceId) {
const { const {
data: speakersResponse, data: events,
isLoading: speakersLoading,
isValidating: speakersValidating,
} = useSpeakers(conferenceId);
const speakers = useMemo(() => addIdAndRelations(speakersResponse || []), [speakersResponse]);
const {
data: tracksResponse,
isLoading: tracksLoading,
isValidating: tracksValidating,
} = useTracks(conferenceId);
const tracks = useMemo(() => addIdAndRelations(tracksResponse || []), [tracksResponse]);
const {
data: eventTypesResponse,
isLoading: eventTypesLoading,
isValidating: eventTypesValidating,
} = useEventTypes(conferenceId);
const eventTypes = useMemo(() => addIdAndRelations(eventTypesResponse || []), [eventTypesResponse]);
const {
data: hallsResponse,
isLoading: hallsLoading,
isValidating: hallsValidating,
} = useHalls(conferenceId);
const halls = useMemo(() => addIdAndRelations(hallsResponse || []), [hallsResponse]);
const {
data: eventsResponse,
isLoading: eventsLoading, isLoading: eventsLoading,
isValidating: eventsValidating, isValidating: eventsValidating,
} = useEvents(conferenceId); } = useEvents(conferenceId);
const events = useMemo(() => addIdAndRelations(eventsResponse || [], [ const {
['event_type', eventTypes, 'event_type_id'], data: speakers,
['track', tracks, 'track_id'], isLoading: speakersLoading,
['participant_users', speakers, 'participant_user_ids'], isValidating: speakersValidating,
]), [eventsResponse, eventTypes, tracks, speakers]); } = useSpeakers(conferenceId);
const { const {
data: slotsResponse, data: tracks,
isLoading: tracksLoading,
isValidating: tracksValidating,
} = useTracks(conferenceId);
const {
data: eventTypes,
isLoading: eventTypesLoading,
isValidating: eventTypesValidating,
} = useEventTypes(conferenceId);
const {
data: halls,
isLoading: hallsLoading,
isValidating: hallsValidating,
} = useHalls(conferenceId);
const {
data: slots,
isLoading: slotsLoading, isLoading: slotsLoading,
isValidating: slotsValidating, isValidating: slotsValidating,
} = useSlots(conferenceId); } = useSlots(conferenceId);
const slots = useMemo(() => addIdAndRelations(slotsResponse || [], [
['hall', halls, 'hall_id'],
['event', events, 'event_id'],
]), [slotsResponse, halls, events]);
const { const {
isStarted: isLoading, isStarted: isLoading,
remainingProgress: loadingProgress, remainingProgress: loadingProgress,
@ -73,10 +53,6 @@ export default function useSchedule(conferenceId) {
remainingProgress: validatingProgress, remainingProgress: validatingProgress,
} = calculateProgress(eventsValidating, speakersValidating, tracksValidating, eventTypesValidating, hallsValidating, slotsValidating); } = calculateProgress(eventsValidating, speakersValidating, tracksValidating, eventTypesValidating, hallsValidating, slotsValidating);
const {
isComplete,
} = calculateProgress(events, speakers, tracks, eventTypes, halls, slots);
return { return {
events, events,
speakers, speakers,
@ -88,6 +64,5 @@ export default function useSchedule(conferenceId) {
loadingProgress, loadingProgress,
isValidating, isValidating,
validatingProgress, validatingProgress,
isComplete,
}; };
} }

View File

@ -14,7 +14,6 @@ export default function useScheduleTable({
cells: [{ cells: [{
id: 1, id: 1,
attributes: { attributes: {
className: 'schedule-'.concat(event.language).concat(' ').concat(event.track.css_class),
colSpan: 2, colSpan: 2,
}, },
event, event,

View File

@ -41,15 +41,3 @@ export function calculateProgress(...elements) {
isNotStarted: completeCount === 0, isNotStarted: completeCount === 0,
}; };
} }
export const addIdAndRelations = (items, relations = []) =>
Object.fromEntries(Object.entries(items).map(([id, item]) =>
([id, {
id,
...item,
...Object.fromEntries(relations.map(([field, collection, idField]) => ([
field,
Array.isArray(item[idField]) ? item[idField].map(id => collection[id]) : collection[item[idField]],
]))),
}])
));