From cc15594035c959243085a6629dbc531797d5b766 Mon Sep 17 00:00:00 2001 From: Caleb Bae Date: Fri, 20 Feb 2026 15:31:27 -0600 Subject: [PATCH 1/2] Add judge notes view popup per project for admin view --- .../admin/tables/ProjectNotesPopup.tsx | 50 +++++++++++++++++++ .../components/admin/tables/ProjectRow.tsx | 7 ++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 client/src/components/admin/tables/ProjectNotesPopup.tsx diff --git a/client/src/components/admin/tables/ProjectNotesPopup.tsx b/client/src/components/admin/tables/ProjectNotesPopup.tsx new file mode 100644 index 0000000..982fbc4 --- /dev/null +++ b/client/src/components/admin/tables/ProjectNotesPopup.tsx @@ -0,0 +1,50 @@ +import { useAdminStore } from '../../../store'; +import InfoPopup from '../../InfoPopup'; + +interface ProjectNotesPopupProps { + enabled: boolean; + setEnabled: React.Dispatch>; + project: Project; +} + +const ProjectNotesPopup = (props: ProjectNotesPopupProps) => { + const judges = useAdminStore((state) => state.judges); + + const judgeNotes = judges + .map((judge) => { + const seenProject = judge.seen_projects.find( + (sp) => sp.project_id === props.project.id + ); + if (seenProject && seenProject.notes && seenProject.notes.trim() !== '') { + return { judgeName: judge.name, notes: seenProject.notes }; + } + return null; + }) + .filter((entry): entry is { judgeName: string; notes: string } => entry !== null); + + return ( + +
+ {judgeNotes.length === 0 ? ( +

+ No judges have left notes for this project. +

+ ) : ( + judgeNotes.map((entry, idx) => ( +
+

{entry.judgeName}

+

{entry.notes}

+
+ )) + )} +
+
+ ); +}; + +export default ProjectNotesPopup; diff --git a/client/src/components/admin/tables/ProjectRow.tsx b/client/src/components/admin/tables/ProjectRow.tsx index 041f766..5f64eeb 100644 --- a/client/src/components/admin/tables/ProjectRow.tsx +++ b/client/src/components/admin/tables/ProjectRow.tsx @@ -9,6 +9,7 @@ import { twMerge } from 'tailwind-merge'; import ActionsDropdown from '../../ActionsDropdown'; import MoveGroupPopup from './MoveGroupPopup'; import MovePopup from './MovePopup'; +import ProjectNotesPopup from './ProjectNotesPopup'; interface ProjectRowProps { project: Project; @@ -24,6 +25,7 @@ const ProjectRow = ({ project, idx }: ProjectRowProps) => { const [deletePopup, setDeletePopup] = useState(false); const [moveGroupPopup, setMoveGroupPopup] = useState(false); const [movePopup, setMovePopup] = useState(false); + const [notesPopup, setNotesPopup] = useState(false); const fetchProjects = useAdminStore((state) => state.fetchProjects); const options = useOptionsStore((state) => state.options); const track = useOptionsStore((state) => state.selectedTrack); @@ -147,6 +149,7 @@ const ProjectRow = ({ project, idx }: ProjectRowProps) => { setOpen={setPopup} actions={[ 'Edit', + 'Notes', project.active ? 'Hide' : 'Unhide', project.prioritized ? 'Unprioritize' : 'Prioritize', 'Move Table', @@ -155,13 +158,14 @@ const ProjectRow = ({ project, idx }: ProjectRowProps) => { ]} actionFunctions={[ setEditPopup.bind(null, true), + setNotesPopup.bind(null, true), hideProject, prioritizeProject, setMovePopup.bind(null, true), setMoveGroupPopup.bind(null, true), setDeletePopup.bind(null, true), ]} - redIndices={[5]} + redIndices={[6]} />
{ + ); }; From ad0a94381ecd96f4ad284ecf3d11185eeb04e380 Mon Sep 17 00:00:00 2001 From: Caleb Bae Date: Fri, 6 Mar 2026 14:06:21 -0600 Subject: [PATCH 2/2] fix: syntax/style changes --- client/src/components/admin/tables/ProjectNotesPopup.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/client/src/components/admin/tables/ProjectNotesPopup.tsx b/client/src/components/admin/tables/ProjectNotesPopup.tsx index 982fbc4..100a097 100644 --- a/client/src/components/admin/tables/ProjectNotesPopup.tsx +++ b/client/src/components/admin/tables/ProjectNotesPopup.tsx @@ -1,6 +1,11 @@ import { useAdminStore } from '../../../store'; import InfoPopup from '../../InfoPopup'; +interface JudgeNote { + judgeName: string; + notes: string; +} + interface ProjectNotesPopupProps { enabled: boolean; setEnabled: React.Dispatch>; @@ -15,12 +20,12 @@ const ProjectNotesPopup = (props: ProjectNotesPopupProps) => { const seenProject = judge.seen_projects.find( (sp) => sp.project_id === props.project.id ); - if (seenProject && seenProject.notes && seenProject.notes.trim() !== '') { + if (seenProject && seenProject.notes && seenProject.notes.trim()) { return { judgeName: judge.name, notes: seenProject.notes }; } return null; }) - .filter((entry): entry is { judgeName: string; notes: string } => entry !== null); + .filter((entry): entry is JudgeNote => !!entry); return (