diff --git a/apps/frontend/locale/en.json b/apps/frontend/locale/en.json index 6366bf46f..5691ab2b0 100644 --- a/apps/frontend/locale/en.json +++ b/apps/frontend/locale/en.json @@ -1177,8 +1177,13 @@ "table": { "match": "Match", "scheduled-time": "Time", + "participant-queued": "Queued", + "participant-present": "Present", "participant-ready": "Ready", - "participant-not-ready": "Not Ready" + "participant-not-ready": "Not Ready", + "participant-no-show": "No Show", + "status-queued": "QUEUED", + "status-present": "PRESENT" } }, "audience-display": { diff --git a/apps/frontend/locale/he.json b/apps/frontend/locale/he.json index 4efad86c3..488d73612 100644 --- a/apps/frontend/locale/he.json +++ b/apps/frontend/locale/he.json @@ -1175,8 +1175,13 @@ "table": { "match": "מקצה", "scheduled-time": "שעה", + "participant-queued": "בקיו", + "participant-present": "נוכחת", "participant-ready": "מוכנה", - "participant-not-ready": "לא מוכנה" + "participant-not-ready": "לא מוכנה", + "participant-no-show": "לא הגיעה", + "status-queued": "בקיו", + "status-present": "נוכחת" } }, "audience-display": { diff --git a/apps/frontend/locale/pl.json b/apps/frontend/locale/pl.json index 6c2ece0e0..21e8e346b 100644 --- a/apps/frontend/locale/pl.json +++ b/apps/frontend/locale/pl.json @@ -1176,8 +1176,13 @@ "table": { "match": "Mecz", "scheduled-time": "Czas", + "participant-queued": "W kolejce", + "participant-present": "Obecny", "participant-ready": "Gotowy", - "participant-not-ready": "Niegotowy" + "participant-not-ready": "Niegotowy", + "participant-no-show": "Nieobecny", + "status-queued": "W KOLEJCE", + "status-present": "OBECNY" } }, "audience-display": { diff --git a/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/desktop-schedule/match-row.tsx b/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/desktop-schedule/match-row.tsx index e9e5cdca1..d6717dbc1 100644 --- a/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/desktop-schedule/match-row.tsx +++ b/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/desktop-schedule/match-row.tsx @@ -5,7 +5,10 @@ import { useTranslations } from 'next-intl'; import dayjs from 'dayjs'; import { TableCell, TableRow, Typography, Tooltip, Stack } from '@mui/material'; import CheckCircleIcon from '@mui/icons-material/CheckCircle'; -import CancelIcon from '@mui/icons-material/Cancel'; +import PersonPinIcon from '@mui/icons-material/PersonPin'; +import HourglassEmptyIcon from '@mui/icons-material/HourglassEmpty'; +import HelpOutlineIcon from '@mui/icons-material/HelpOutline'; +import BlockIcon from '@mui/icons-material/Block'; import type { Match, Scoresheet, Table as TableType } from '../../graphql/types'; import { ScoresheetStatusButton } from '../scoresheet-status-button'; @@ -112,6 +115,8 @@ export function MatchRow({ teamNumber={participant.team.number} teamSlug={participant.team.slug} teamName={participant.team.name} + teamAffiliation={participant.team.affiliation} + teamCity={participant.team.city} scoresheetSlug={scoresheet.slug} status={scoresheet.status} escalated={scoresheet.escalated} @@ -125,14 +130,60 @@ export function MatchRow({ } // Show participant readiness state for non-completed matches + const isQueued = participant.queued; + const isPresent = participant.present; const isReady = participant.ready; + // Determine participant status + const getParticipantStatus = () => { + if (!participant.team?.arrived) return 'no-show'; + if (isReady) return 'ready'; + if (isPresent) return 'present'; + if (isQueued) return 'queued'; + return 'missing'; + }; + + const status = getParticipantStatus(); + + const getStatusIcon = () => { + const iconProps = { sx: { fontSize: '1.25rem' } }; + switch (status) { + case 'ready': + return ; + case 'present': + return ; + case 'queued': + return ; + case 'no-show': + return ; + case 'missing': + return ; + default: + return null; + } + }; + // Show icons only for the loaded match const showIcon = isLoaded; // Check if team matches search filter const isTeamFiltered = doesTeamMatchSearch(participant.team.number, participant.team.name); + let tooltipTitle = `${participant.team.affiliation} • ${participant.team.city}`; + if (isLoaded) { + const statuses = []; + if (isQueued) statuses.push(t('table.participant-queued')); + if (isPresent) statuses.push(t('table.participant-present')); + if (isReady) statuses.push(t('table.participant-ready')); + if (statuses.length > 0) { + tooltipTitle = statuses.join(' • '); + } else if (status === 'no-show') { + tooltipTitle = t('table.participant-no-show'); + } else { + tooltipTitle = t('table.participant-not-ready'); + } + } + return ( - + - {showIcon && - (isReady ? ( - - ) : ( - - ))} + {showIcon && ( + + {getStatusIcon()} + + )} { + if (!participant.team!.arrived) return 'no-show'; + if (isReady) return 'ready'; + if (isPresent) return 'present'; + if (isQueued) return 'queued'; + return 'missing'; + }; + + const status = getParticipantStatus(); + + // Get status icon + const getStatusIcon = () => { + const iconProps = { sx: { fontSize: '1.5rem' } }; + switch (status) { + case 'ready': + return ; + case 'present': + return ; + case 'queued': + return ; + case 'no-show': + return ; + case 'missing': + return ; + default: + return null; + } + }; + // Show icons only for the loaded match const showIcon = isLoaded; + // Build tooltip based on status + let tooltipTitle = `${participant.team!.affiliation} • ${participant.team!.city}`; + if (isLoaded) { + const statuses = []; + if (isQueued) statuses.push(t('table.participant-queued')); + if (isPresent) statuses.push(t('table.participant-present')); + if (isReady) statuses.push(t('table.participant-ready')); + if (statuses.length > 0) { + tooltipTitle = statuses.join(' • '); + } else if (status === 'no-show') { + tooltipTitle = t('table.participant-no-show'); + } else { + tooltipTitle = t('table.participant-not-ready'); + } + } + return ( - + - {participant.team!.name} + {participant.team!.name} #{participant.team!.number} + {participant.team!.region && ( + <> + {' '} + + + )} - {showIcon && - (isReady ? ( - - ) : ( - - ))} + {showIcon && getStatusIcon()} ); diff --git a/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/scoresheet-status-button.tsx b/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/scoresheet-status-button.tsx index 8c57dfdd0..f206c2760 100644 --- a/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/scoresheet-status-button.tsx +++ b/apps/frontend/src/app/[locale]/lems/(volunteer)/(dashboard)/head-referee/components/scoresheet-status-button.tsx @@ -16,6 +16,8 @@ export interface ScoresheetStatusButtonProps { teamNumber: string; teamSlug: string; teamName: string; + teamAffiliation?: string; + teamCity?: string; scoresheetSlug: string; status: ScoresheetStatus; escalated: boolean; @@ -80,6 +82,8 @@ export function ScoresheetStatusButton({ teamNumber, teamSlug, teamName, + teamAffiliation, + teamCity, scoresheetSlug, status, escalated, @@ -96,7 +100,7 @@ export function ScoresheetStatusButton({ const textColor = isSubmitted ? 'common.white' : statusColor; - const tooltipTitle = teamName; + const tooltipTitle = teamAffiliation && teamCity ? `${teamAffiliation} • ${teamCity}` : teamName; const button = ( - - #{teamNumber} - + + + #{teamNumber} + + + {teamName} + + {(score !== undefined || gp) && (