Skip to content

Commit

Permalink
initial schedule parameters finished
Browse files Browse the repository at this point in the history
  • Loading branch information
kyle-flynn committed Mar 25, 2024
1 parent 112bd25 commit 0207db6
Show file tree
Hide file tree
Showing 12 changed files with 585 additions and 42 deletions.
11 changes: 11 additions & 0 deletions front-end/src/api/use-schedule-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,14 @@ export const useScheduleForTournament = (
: undefined,
(url) => apiFetcher(url, 'GET')
);

export const useScheduleItemsForTournament = (
eventKey: string | null | undefined,
tournamentKey: string | null | undefined
) =>
useSWR<ScheduleItem[]>(
eventKey && tournamentKey
? `schedule/${eventKey}/${tournamentKey}`
: undefined,
(url) => apiFetcher(url, 'GET')
);
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'src/stores/NewRecoil';
import {
calculateTotalMatches,
useScheduleValidator,
getScheduleValidation,
generateScheduleItems
} from '@toa-lib/models';
import Days from '../time/Days';
Expand All @@ -30,7 +30,7 @@ const SetupSchedule: FC = () => {
);

const [flags, setFlag] = useFlags();
const { valid, validationMessage } = useScheduleValidator(schedule);
const { valid, validationMessage } = getScheduleValidation(schedule);

useEffect(() => {
setSchedule((prev) => ({
Expand Down
47 changes: 27 additions & 20 deletions front-end/src/apps/schedules/options/default-options.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,32 @@
import { Grid, TextField } from '@mui/material';
import { EventSchedule } from '@toa-lib/models';
import { ChangeEvent, FC } from 'react';
import { EventSchedule, calculateTotalMatches } from '@toa-lib/models';
import { ChangeEvent, FC, useEffect } from 'react';

interface Props {
eventSchedule: EventSchedule;
eventSchedule?: EventSchedule;
disabled?: boolean;
onChange: (schedule: EventSchedule) => void;
}

export const DefaultScheduleOptions: FC<Props> = ({
eventSchedule,
disabled,
onChange
}) => {
useEffect(() => {
if (!eventSchedule) return;
onChange({
...eventSchedule,
totalMatches: calculateTotalMatches(eventSchedule)
});
}, [
eventSchedule?.matchesPerTeam,
eventSchedule?.teamsPerAlliance,
eventSchedule?.playoffsOptions
]);

const handleChange = (event: ChangeEvent<HTMLInputElement>) => {
if (!eventSchedule) return;
const value = parseInt(event.target.value);
const { name } = event.target;
onChange({
Expand All @@ -26,20 +41,12 @@ export const DefaultScheduleOptions: FC<Props> = ({
spacing={3}
sx={{ marginBottom: (theme) => theme.spacing(2) }}
>
<Grid item xs={12} sm={6} md={4} lg={3}>
<TextField
label='Teams Scheduled'
value={eventSchedule.teams.length}
disabled
fullWidth
type='number'
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<TextField
name='cycleTime'
label='Cycle Time'
value={eventSchedule.cycleTime}
value={eventSchedule?.cycleTime}
disabled={disabled}
fullWidth
onChange={handleChange}
type='number'
Expand All @@ -49,28 +56,28 @@ export const DefaultScheduleOptions: FC<Props> = ({
<TextField
name='matchesPerTeam'
label='Matches Per Team'
value={eventSchedule.matchesPerTeam}
value={eventSchedule?.matchesPerTeam}
disabled={disabled}
fullWidth
onChange={handleChange}
type='number'
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<TextField
label='Total Matches'
value={eventSchedule.totalMatches}
label='Teams Scheduled'
value={eventSchedule?.teamsParticipating}
disabled
fullWidth
type='number'
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={3}>
<TextField
name='matchConcurrency'
label='Match Concurrency'
value={eventSchedule.matchConcurrency}
label='Total Matches'
value={eventSchedule?.totalMatches}
disabled
fullWidth
onChange={handleChange}
type='number'
/>
</Grid>
Expand Down
149 changes: 149 additions & 0 deletions front-end/src/apps/schedules/schedule-break.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { Grid, TextField } from '@mui/material';
import { DateTimePicker } from '@mui/x-date-pickers';
import { EventSchedule, DayBreak } from '@toa-lib/models';
import { DateTime } from 'luxon';
import { FC, useState } from 'react';

interface Props {
eventSchedule: EventSchedule;
dayId: number;
breakId: number;
disabled?: boolean;
onChange: (schedule: EventSchedule) => void;
}

export const ScheduleBreak: FC<Props> = ({
dayId,
breakId,
eventSchedule,
disabled,
onChange
}) => {
const day = eventSchedule.days[dayId];
const dayBreak = day.breaks[breakId];
const [startDate, setStartDate] = useState<DateTime | null>(DateTime.now());
const [endDate, setEndDate] = useState<DateTime | null>(DateTime.now());

const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const { name, value, type } = event.target;
const newBreak = {
...dayBreak,
[name]: type === 'number' ? parseInt(value) : value
};
const newStartTime = DateTime.fromISO(day.startTime).plus({
minutes:
Math.ceil(newBreak.afterMatch / eventSchedule.matchConcurrency) *
eventSchedule.cycleTime
});
const newEndTime = newStartTime.plus({
minutes: newBreak.duration
});
newBreak.startTime = newStartTime.toISO() ?? '';
newBreak.endTime = newEndTime.toISO() ?? '';
const endDateTime = getEndDate(newBreak);
setStartDate(newStartTime);
setEndDate(newEndTime);
updateScheduleDayBreak(newBreak, endDateTime);
};

const getEndDate = (dayBreak: DayBreak): DateTime => {
// First make the end date time by adding the duration to the start time
const endDateTime = DateTime.fromISO(eventSchedule.days[dayId].endTime);
// Second create a new breaks array with the updated break
const newBreaks = eventSchedule.days[dayId].breaks.map((b) =>
b.id === breakId ? dayBreak : b
);
// Third calculate the new breaks duration by subtracting the old breaks duration from the new breaks duration
const oldBreaksDuration =
day.breaks.length > 0
? day.breaks
.map((dayBreak) => dayBreak.duration)
.reduce((prev, curr) => prev + curr)
: 0;
const breaksDuration =
newBreaks.length > 0
? newBreaks
.map((dayBreak) => dayBreak.duration)
.reduce((prev, curr) => prev + curr)
: 0;
return endDateTime.plus({ minutes: breaksDuration - oldBreaksDuration });
};

const updateScheduleDayBreak = (dayBreak: DayBreak, newEndTime: DateTime) => {
const dayBreaks = eventSchedule.days[dayId].breaks;
const newSchedule = {
...eventSchedule,
days: eventSchedule.days.map((d) =>
d.id === dayId
? {
...d,
endTime: newEndTime.toISO() ?? '',
breaks: dayBreaks.map((b) => (b.id === breakId ? dayBreak : b))
}
: d
)
};
onChange(newSchedule);
};

return (
<Grid
key={`day=${day.id}-break-${dayBreak.id}`}
container
spacing={3}
sx={{
paddingTop: (theme) => theme.spacing(1),
paddingBottom: (theme) => theme.spacing(2)
}}
>
<Grid item xs={12} sm={6} md={4} lg={2}>
<TextField
name='name'
label='Break Name'
value={dayBreak.name}
fullWidth
onChange={handleChange}
disabled={disabled}
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={1}>
<TextField
name='afterMatch'
label='Match'
value={dayBreak.afterMatch}
fullWidth
onChange={handleChange}
type='number'
disabled={disabled}
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={1}>
<TextField
name='duration'
label='Duration'
value={dayBreak.duration}
fullWidth
onChange={handleChange}
type='number'
disabled={disabled}
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={4}>
<DateTimePicker
label='Start Date'
value={startDate}
disabled
slotProps={{ textField: { fullWidth: true } }}
/>
</Grid>
<Grid item xs={12} sm={6} md={4} lg={4}>
<DateTimePicker
label='End Date'
value={endDate}
disabled
slotProps={{ textField: { fullWidth: true } }}
/>
</Grid>
</Grid>
);
};
Loading

0 comments on commit 0207db6

Please sign in to comment.