Compare commits

...

5 Commits

Author SHA1 Message Date
Vencislav Atanasov 4774dcda11 Fix propTypes 2024-09-22 02:42:16 +03:00
Vencislav Atanasov 86833b5276 Fix schedule chooser 2024-09-22 02:30:16 +03:00
Vencislav Atanasov 24bcaa6d23 Sample event rendering 2024-09-22 02:08:52 +03:00
Vencislav Atanasov 78064e3f8f Move schedule components to a separate directory 2024-09-22 01:59:04 +03:00
Vencislav Atanasov ad782899b2 Switch to light theme 2024-09-22 00:07:24 +03:00
13 changed files with 75 additions and 66 deletions

View File

@ -1,4 +1,4 @@
import ScheduleChooser from './ScheduleChooser.jsx'; import ScheduleChooser from './Schedule/ScheduleChooser.jsx';
function App() { function App() {
return (<ScheduleChooser/>); return (<ScheduleChooser/>);

View File

@ -1,3 +0,0 @@
export default function Event() {
}

11
src/Schedule/Event.jsx Normal file
View File

@ -0,0 +1,11 @@
import PropTypes from 'prop-types';
export default function Event({
title,
}) {
return (<strong>{title}</strong>);
}
Event.propTypes = {
title: PropTypes.string.isRequired,
};

View File

@ -1,10 +1,10 @@
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 } 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';
import './Schedule.scss'; import './Schedule.scss';
import { langs } from './constants.js'; import { langs } from './constants.js';
@ -33,8 +33,9 @@ export default function Schedule({
}); });
return (<> return (<>
{isLoading && <>Loading... <progress value={loadingProgress} /></>} {isLoading && <progress value={loadingProgress}/>}
<div className="schedule"> <div className="schedule">
<hr />
{header && rows && <> {header && rows && <>
<table> <table>
<thead> <thead>

View File

@ -71,11 +71,11 @@
} }
.schedule-en::after { .schedule-en::after {
background: url('./assets/en_US.png'); background: url('../assets/en_US.png');
} }
.schedule-bg::after { .schedule-bg::after {
background: url('./assets/bg_BG.png'); background: url('../assets/bg_BG.png');
} }
.schedule-avatar { .schedule-avatar {

View File

@ -0,0 +1,37 @@
import ScheduleLoader from './ScheduleLoader.jsx';
import { langs } from './constants.js';
import { useMemo, useState } from 'react';
import { dateSorter } from '../utils.js';
import useConferences from '../hooks/useConferences.js';
import { getConferenceYear } from './utils.js';
export default function ScheduleChooser() {
const {
data,
error,
isLoading,
} = useConferences();
const conferences = useMemo(() => Array.isArray(data) ? data.sort(dateSorter('start_date')) : data, [data]);
const [ year, setYear ] = useState(2023);
const [ lang, setLang ] = useState('bg');
return (<>
{isLoading && <p>Please wait...</p>}
{error && <p>Error: {error}</p>}
{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>)}
</select>
</>}
{Object.entries(langs).map(([langId, langName]) =>
<label key={langId}>
<input type="radio" checked={langId === lang} onChange={e =>
setLang(e.target.value)} name="lang" value={langId} />
{langName}
</label>)}
<ScheduleLoader year={year} lang={lang} />
</>);
}

View File

@ -1,4 +1,4 @@
import useConferences from './hooks/useConferences.js'; import useConferences from '../hooks/useConferences.js';
import Schedule from './Schedule.jsx'; import Schedule from './Schedule.jsx';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useMemo } from 'react'; import { useMemo } from 'react';
@ -27,6 +27,6 @@ export default function ScheduleLoader({
} }
ScheduleLoader.propTypes = { ScheduleLoader.propTypes = {
year: PropTypes.number, year: PropTypes.number.isRequired,
lang: PropTypes.string, lang: PropTypes.string.isRequired,
}; };

5
src/Schedule/utils.js Normal file
View File

@ -0,0 +1,5 @@
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 === 'Други';

View File

@ -1,44 +0,0 @@
import PropTypes from 'prop-types';
import ScheduleLoader from './ScheduleLoader.jsx';
export default function ScheduleChooser({
year = 2023,
lang = 'bg',
}) {
/*
const {
data,
error,
isLoading,
} = useConferences();
const conferences = useMemo(() => Array.isArray(data) ? data.sort(dateSorter('start_date')) : data, [data]);
const [ selectedConferenceId, setSelectedConferenceId ] = useState();
const [ selectedLang, setSelectedLang ] = useState(lang);
return (<>
<div>
<select onChange={e => setSelectedLang(e.target.value)}>
{Object.entries(langs).map(([langId, langName]) => <option key={langId} value={langId}>{langName}</option>)}
</select>
</div>
{isLoading && <p>Please wait...</p>}
{error && <p>Error: {error}</p>}
{conferences && <>
<label>Select a conference</label>
<select onChange={e => setSelectedConferenceId(e.target.value)}>
{conferences.map(conference => <option key={conference.id}
value={conference.id}>{conference.title}</option>)}
</select>
</>}
<ScheduleLoader year={year} lang={selectedLang} />
</>);
*/
return (<ScheduleLoader year={year} lang={lang} />);
}
ScheduleChooser.propTypes = {
year: PropTypes.number,
lang: PropTypes.string,
};

View File

@ -1,4 +1,5 @@
export default function useScheduleTable({ export default function useScheduleTable({
events = {},
halls = {}, halls = {},
lang, lang,
}) { }) {
@ -8,7 +9,16 @@ export default function useScheduleTable({
name: hall.name[lang], name: hall.name[lang],
})); }));
const rows = []; const rows = Object.entries(events).map(([eventId, event]) => ({
id: eventId,
cells: [{
id: 1,
attributes: {
colSpan: 2,
},
event,
}],
}));
return { return {
header, header,

View File

@ -3,10 +3,6 @@
line-height: 1.5; line-height: 1.5;
font-weight: 400; font-weight: 400;
color-scheme: light dark;
color: rgba(255, 255, 255, 0.87);
background-color: #242424;
font-synthesis: none; font-synthesis: none;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;

View File

@ -9,10 +9,6 @@ function sorter(a, b, fieldFn) {
export const dateSorter = key => (a, b) => sorter(a, b, item => Date.parse(item[key])); export const dateSorter = key => (a, b) => sorter(a, b, item => Date.parse(item[key]));
export const getSpeakerName = speaker => speaker.first_name.concat(' ').concat(speaker.last_name);
export const isTrackHidden = track => track.name.en === 'Other' || track.name.bg === 'Други';
export function calculateProgress(...elements) { export function calculateProgress(...elements) {
const totalCount = elements.length; const totalCount = elements.length;