From d54c7d56670c438c8bd4f705ce5dfe203d801a6d Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Sun, 2 Nov 2025 09:57:30 -0600 Subject: [PATCH 1/4] Fix issue where deliberation check is wrong --- client/src/pages/judge/live.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/pages/judge/live.tsx b/client/src/pages/judge/live.tsx index 769b44e..41a241b 100644 --- a/client/src/pages/judge/live.tsx +++ b/client/src/pages/judge/live.tsx @@ -100,7 +100,7 @@ const JudgeLive = () => { } // Check to see if deliberation has started - const deliberationRes = await getRequest('/admin/deliberation', ''); + const deliberationRes = await getRequest('/judge/deliberation', 'judge'); if (deliberationRes.status !== 200) { errorAlert(deliberationRes); return; From 8e72488edcbbd23cd9de3e9eb8d461e048aada8c Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Sun, 2 Nov 2025 10:04:08 -0600 Subject: [PATCH 2/4] Create group info store --- .../src/components/judge/ProjectDisplay.tsx | 10 ++++- client/src/pages/Expo.tsx | 11 ++--- client/src/pages/judge/live.tsx | 5 +++ client/src/store.tsx | 45 +++++++++++++++---- 4 files changed, 54 insertions(+), 17 deletions(-) diff --git a/client/src/components/judge/ProjectDisplay.tsx b/client/src/components/judge/ProjectDisplay.tsx index 71e189a..b7b4d73 100644 --- a/client/src/components/judge/ProjectDisplay.tsx +++ b/client/src/components/judge/ProjectDisplay.tsx @@ -3,6 +3,7 @@ import { twMerge } from 'tailwind-merge'; import Paragraph from '../Paragraph'; import { getRequest } from '../../api'; import { errorAlert } from '../../util'; +import { useGroupInfoStore } from '../../store'; interface ProjectDisplayProps { /* Project ID to display */ @@ -17,6 +18,8 @@ interface ProjectDisplayProps { const ProjectDisplay = (props: ProjectDisplayProps) => { const [project, setProject] = useState(null); + const groupsEnabled = useGroupInfoStore((state) => state.enabled); + const groupNames = useGroupInfoStore((state) => state.names); useEffect(() => { async function fetchData() { @@ -46,7 +49,12 @@ const ProjectDisplay = (props: ProjectDisplayProps) => { {project.name} -

Table {project.location}

+

+ Table {project.location} + {groupsEnabled && ( + [{groupNames[project.group]}] + )} +

); diff --git a/client/src/pages/Expo.tsx b/client/src/pages/Expo.tsx index 7acbe07..a142247 100644 --- a/client/src/pages/Expo.tsx +++ b/client/src/pages/Expo.tsx @@ -6,6 +6,7 @@ import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; import Dropdown from '../components/Dropdown'; import Button from '../components/Button'; import { Helmet } from 'react-helmet'; +import { useGroupInfoStore } from '../store'; const Expo = () => { const { track: trackParam } = useParams(); @@ -14,7 +15,7 @@ const Expo = () => { const [nameSort, setNameSort] = useState(false); const [track, setTrack] = useState(''); const [challenges, setChallenges] = useState([]); - const [groupInfo, setGroupInfo] = useState({ enabled: false, names: [] }); + const groupInfo = useGroupInfoStore(); const [searchParams, _] = useSearchParams(); const navigate = useNavigate(); @@ -36,13 +37,7 @@ const Expo = () => { return; } - const groupRes = await getRequest('/group-info', ''); - if (groupRes.status !== 200) { - errorAlert(groupRes); - return; - } - const gi = groupRes.data as GroupInfo; - setGroupInfo({ enabled: gi.enabled && gi.names.length > 0, names: gi.names }); + await groupInfo.fetchGroupInfo(); setChallenges(['', ...(res.data as string[])]); } diff --git a/client/src/pages/judge/live.tsx b/client/src/pages/judge/live.tsx index 41a241b..498ea93 100644 --- a/client/src/pages/judge/live.tsx +++ b/client/src/pages/judge/live.tsx @@ -18,6 +18,7 @@ import alarm from '../../assets/alarm.mp3'; import data from '../../data.json'; import TextInput from '../../components/TextInput'; import { Helmet } from 'react-helmet'; +import { useGroupInfoStore } from '../../store'; const infoPages = ['paused', 'hidden', 'no-projects', 'done', 'doneTrack']; const infoData = [ @@ -32,6 +33,7 @@ const audio = new Audio(alarm); const JudgeLive = () => { const navigate = useNavigate(); + const fetchGroupInfo = useGroupInfoStore((state) => state.fetchGroupInfo); const [verified, setVerified] = useState(false); const [judge, setJudge] = useState(null); const [finishPopup, setFinishPopup] = useState(false); @@ -134,6 +136,9 @@ const JudgeLive = () => { return; } + // Fetch group info + await fetchGroupInfo(); + // If the judge has a current project, use that if (theJudge.current) { setJudge(theJudge); diff --git a/client/src/store.tsx b/client/src/store.tsx index fedb01c..19c18c2 100644 --- a/client/src/store.tsx +++ b/client/src/store.tsx @@ -149,7 +149,7 @@ const useOptionsStore = create((set) => ({ group_names: [], ignore_tracks: [], block_reqs: false, - max_req_per_min: 0 + max_req_per_min: 0, }, selectedTrack: '', @@ -193,12 +193,12 @@ const useFlagsStore = create((set) => ({ })); interface AdminTableStore { - projects: Project[], - judges: Judge[], - selected: boolean[], - setProjects: (projects: Project[]) => void, - setJudges: (judges: Judge[]) => void, - setSelected: (selected: boolean[]) => void, + projects: Project[]; + judges: Judge[]; + selected: boolean[]; + setProjects: (projects: Project[]) => void; + setJudges: (judges: Judge[]) => void; + setSelected: (selected: boolean[]) => void; } const useAdminTableStore = create((set) => ({ @@ -219,4 +219,33 @@ const useAdminTableStore = create((set) => ({ }, })); -export { useAdminStore, useClockStore, useOptionsStore, useFlagsStore, useAdminTableStore }; +interface GroupInfoStore { + names: string[]; + enabled: boolean; + fetchGroupInfo: () => Promise; +} + +const useGroupInfoStore = create((set) => ({ + names: [], + enabled: false, + + fetchGroupInfo: async () => { + const groupRes = await getRequest('/group-info', ''); + if (groupRes.status !== 200) { + errorAlert(groupRes); + return; + } + const groupInfo = groupRes.data as GroupInfo; + console.log(groupInfo) + set({ names: groupInfo.names, enabled: groupInfo.enabled && groupInfo.names.length > 0 }); + }, +})); + +export { + useAdminStore, + useClockStore, + useOptionsStore, + useFlagsStore, + useAdminTableStore, + useGroupInfoStore, +}; From 89ba854c556d9598a9ccdbacbf61f5cc45c9cb40 Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Sun, 2 Nov 2025 10:12:23 -0600 Subject: [PATCH 3/4] Minor UI spacing tweaks to live judge page --- client/src/components/judge/ProjectDisplay.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/src/components/judge/ProjectDisplay.tsx b/client/src/components/judge/ProjectDisplay.tsx index b7b4d73..1dee37d 100644 --- a/client/src/components/judge/ProjectDisplay.tsx +++ b/client/src/components/judge/ProjectDisplay.tsx @@ -44,12 +44,12 @@ const ProjectDisplay = (props: ProjectDisplayProps) => { return (
-

+

{project.name}

-

+

Table {project.location} {groupsEnabled && ( [{groupNames[project.group]}] From f1893976d5bfc3b66d1f49f8e069919d44c9e1a2 Mon Sep 17 00:00:00 2001 From: Michael Zhao Date: Sun, 2 Nov 2025 10:28:00 -0600 Subject: [PATCH 4/4] Fixed issue with state not reloading --- client/src/pages/admin/settings.tsx | 32 ++++++++++++++--------------- client/src/store.tsx | 8 +++++--- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/client/src/pages/admin/settings.tsx b/client/src/pages/admin/settings.tsx index 4065df0..8904f03 100644 --- a/client/src/pages/admin/settings.tsx +++ b/client/src/pages/admin/settings.tsx @@ -102,10 +102,10 @@ const AdminSettings = () => { const navigate = useNavigate(); async function getOptions() { - await fetchOptions(); + const newOptions = await fetchOptions() ?? options; // Calculate judging timer MM:SS - const timer = options.judging_timer; + const timer = newOptions.judging_timer; if (timer) { const minutes = Math.floor(timer / 60); const seconds = timer % 60; @@ -114,24 +114,24 @@ const AdminSettings = () => { } // Set min views - setMinViews(options.min_views); + setMinViews(newOptions.min_views); // Set sync clock - setSyncClock(options.clock_sync); + setSyncClock(newOptions.clock_sync); // Set group options - setMultiGroup(options.multi_group); - setNumGroups(options.num_groups); - setGroupSizes(options.group_sizes.join(', ')); - setSwitchingMode(options.switching_mode); - setAutoSwitchProp(options.auto_switch_prop); - setJudgeTracks(options.judge_tracks); - setTracks(options.tracks.join(', ')); - setTrackViews(options.track_views.join(', ')); - setGroupNames(options.group_names.join(', ')); - setIgnoreTracks(options.ignore_tracks.join(', ')); - setBlockReqs(options.block_reqs); - setMaxReqPerMin(options.max_req_per_min); + setMultiGroup(newOptions.multi_group); + setNumGroups(newOptions.num_groups); + setGroupSizes(newOptions.group_sizes.join(', ')); + setSwitchingMode(newOptions.switching_mode); + setAutoSwitchProp(newOptions.auto_switch_prop); + setJudgeTracks(newOptions.judge_tracks); + setTracks(newOptions.tracks.join(', ')); + setTrackViews(newOptions.track_views.join(', ')); + setGroupNames(newOptions.group_names.join(', ')); + setIgnoreTracks(newOptions.ignore_tracks.join(', ')); + setBlockReqs(newOptions.block_reqs); + setMaxReqPerMin(newOptions.max_req_per_min); // Get active clock status await fetchClock(); diff --git a/client/src/store.tsx b/client/src/store.tsx index 19c18c2..6086cb2 100644 --- a/client/src/store.tsx +++ b/client/src/store.tsx @@ -121,7 +121,7 @@ const useClockStore = create()((set) => ({ interface OptionsStore { options: Options; selectedTrack: string; - fetchOptions: () => Promise; + fetchOptions: () => Promise; setSelectedTrack: (track: string) => void; } @@ -158,9 +158,11 @@ const useOptionsStore = create((set) => ({ const optionsRes = await getRequest('/admin/options', 'admin'); if (optionsRes.status !== 200) { errorAlert(optionsRes); - return; + return null; } - set({ options: optionsRes.data as Options }); + const data = optionsRes.data as Options; + set({ options: data }); + return data; }, setSelectedTrack: async (track: string) => {