From 5aa64007bd0f3333a569d363617330119fdb96a4 Mon Sep 17 00:00:00 2001 From: Kyle Flynn Date: Wed, 27 Mar 2024 02:01:38 -0400 Subject: [PATCH] starting on the new scorekeeper app --- front-end/src/AppRoutes.tsx | 13 ++-- front-end/src/apps/scorekeeper/index.ts | 3 + .../match-control/alliance-card.tsx | 60 +++++++++++++++++++ .../match-control/match-control-header.tsx | 28 +++++++++ .../match-control/match-status.tsx | 35 +++++++++++ .../match-control/prestart-button.tsx | 22 +++++++ .../src/apps/scorekeeper/scorekeeper-app.tsx | 31 ++++++++++ lib/models/src/base/Match.ts | 3 + 8 files changed, 191 insertions(+), 4 deletions(-) create mode 100644 front-end/src/apps/scorekeeper/index.ts create mode 100644 front-end/src/apps/scorekeeper/match-control/alliance-card.tsx create mode 100644 front-end/src/apps/scorekeeper/match-control/match-control-header.tsx create mode 100644 front-end/src/apps/scorekeeper/match-control/match-status.tsx create mode 100644 front-end/src/apps/scorekeeper/match-control/prestart-button.tsx create mode 100644 front-end/src/apps/scorekeeper/scorekeeper-app.tsx diff --git a/front-end/src/AppRoutes.tsx b/front-end/src/AppRoutes.tsx index 56eb8b46..e6a299de 100644 --- a/front-end/src/AppRoutes.tsx +++ b/front-end/src/AppRoutes.tsx @@ -30,14 +30,19 @@ const TournamentEditor = lazy(() => import('./apps/tournaments').then((m) => ({ default: m.TournamentEditor })) ); +// Schedule Routes const ScheduleManager = lazy(() => import('./apps/schedules').then((m) => ({ default: m.ScheduleManager })) ); +// Scorekeeper Routes +const ScorekeeperApp = lazy(() => + import('./apps/scorekeeper').then((m) => ({ default: m.ScorekeeperApp })) +); + const SettingsApp = lazy(() => import('./apps/Settings')); const GlobalSettingsApp = lazy(() => import('./apps/Settings/GlobalSettings')); -const ScoringApp = lazy(() => import('./apps/Scoring')); const AudienceDisplay = lazy(() => import('./apps/AudienceDisplay')); const RefereeApp = lazy(() => import('./apps/Referee/Referee')); const RedReferee = lazy(() => import('./apps/Referee/RedReferee')); @@ -145,10 +150,10 @@ const AppRoutes: AppRoute[] = [ element: ScheduleManager }, { - name: 'Scoring App', - path: '/:eventKey/scoring', + name: 'Scorekeeper App', + path: '/:eventKey/scorekeeper', group: 0, - element: ScoringApp + element: ScorekeeperApp }, { name: 'Settings', diff --git a/front-end/src/apps/scorekeeper/index.ts b/front-end/src/apps/scorekeeper/index.ts new file mode 100644 index 00000000..8e812085 --- /dev/null +++ b/front-end/src/apps/scorekeeper/index.ts @@ -0,0 +1,3 @@ +import { ScorekeeperApp } from './scorekeeper-app'; + +export { ScorekeeperApp }; diff --git a/front-end/src/apps/scorekeeper/match-control/alliance-card.tsx b/front-end/src/apps/scorekeeper/match-control/alliance-card.tsx new file mode 100644 index 00000000..db9e83f2 --- /dev/null +++ b/front-end/src/apps/scorekeeper/match-control/alliance-card.tsx @@ -0,0 +1,60 @@ +import { Grid, Paper, Typography } from '@mui/material'; +import { Alliance, BLUE_STATION, MatchParticipant } from '@toa-lib/models'; +import { FC } from 'react'; + +interface Props { + alliance: Alliance; + participants?: MatchParticipant[]; +} + +export const AllianceCard: FC = ({ alliance, participants }) => { + const allianceParticipants = participants + ? participants.filter((p) => + alliance === 'red' + ? p.station < BLUE_STATION + : p.station >= BLUE_STATION + ) + : []; + return ( + theme.spacing(1) }} + > + + + + Team + + + + + Card Status + + + + + No Show + + + + + DQ + + + + {allianceParticipants.map((p) => ( + + + {/* */} + + + {/* */} + + + {/* */} + + + ))} + + ); +}; diff --git a/front-end/src/apps/scorekeeper/match-control/match-control-header.tsx b/front-end/src/apps/scorekeeper/match-control/match-control-header.tsx new file mode 100644 index 00000000..50c1cd03 --- /dev/null +++ b/front-end/src/apps/scorekeeper/match-control/match-control-header.tsx @@ -0,0 +1,28 @@ +import { Grid } from '@mui/material'; +import { FC } from 'react'; +import { PrestartButton } from './prestart-button'; + +export const MatchControlHeader: FC = () => { + return ( + + + + + + AudienceDisplayButton + + + FieldPrepButton + + + StartMatchButton + + + CommitScoresButton + + + PostResultsButton + + + ); +}; diff --git a/front-end/src/apps/scorekeeper/match-control/match-status.tsx b/front-end/src/apps/scorekeeper/match-control/match-status.tsx new file mode 100644 index 00000000..3ce787f3 --- /dev/null +++ b/front-end/src/apps/scorekeeper/match-control/match-status.tsx @@ -0,0 +1,35 @@ +import { Box, Chip, Divider, Paper, Typography } from '@mui/material'; +import { FC } from 'react'; +import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; + +export const MatchStatus: FC = () => { + return ( + + theme.spacing(2), + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }} + > + Match Status + } + label='Match Started' + color='primary' + variant='outlined' + /> + + + theme.spacing(2) }}> + + Match Status + + + Match Countdown + + + + ); +}; diff --git a/front-end/src/apps/scorekeeper/match-control/prestart-button.tsx b/front-end/src/apps/scorekeeper/match-control/prestart-button.tsx new file mode 100644 index 00000000..722036e8 --- /dev/null +++ b/front-end/src/apps/scorekeeper/match-control/prestart-button.tsx @@ -0,0 +1,22 @@ +import { Button } from '@mui/material'; +import { FC, useState } from 'react'; + +export const PrestartButton: FC = () => { + const [canPrestart, setCanPrestart] = useState(true); + const prestart = () => setCanPrestart(false); + const cancelPrestart = () => setCanPrestart(true); + return canPrestart ? ( + + ) : ( + + ); +}; diff --git a/front-end/src/apps/scorekeeper/scorekeeper-app.tsx b/front-end/src/apps/scorekeeper/scorekeeper-app.tsx new file mode 100644 index 00000000..d0d4a0f3 --- /dev/null +++ b/front-end/src/apps/scorekeeper/scorekeeper-app.tsx @@ -0,0 +1,31 @@ +import { FC } from 'react'; +import { useCurrentEvent } from 'src/api/use-event-data'; +import DefaultLayout from 'src/layouts/DefaultLayout'; +import { MatchControlHeader } from './match-control/match-control-header'; +import { Grid } from '@mui/material'; +import { AllianceCard } from './match-control/alliance-card'; + +export const ScorekeeperApp: FC = () => { + const { data: event } = useCurrentEvent(); + return ( + + theme.spacing(2) }} + > + + + + + + + + + + ); +}; diff --git a/lib/models/src/base/Match.ts b/lib/models/src/base/Match.ts index e20dad68..c832891f 100644 --- a/lib/models/src/base/Match.ts +++ b/lib/models/src/base/Match.ts @@ -23,6 +23,9 @@ export const RESULT_GAME_SPECIFIC = 3; export type Alliance = 'red' | 'blue'; +export const RED_STATION = 10; +export const BLUE_STATION = 20; + export enum MatchState { MATCH_NOT_SELECTED = 0, PRESTART_READY = 1,