From 0ca2894e1079dcf05ca89dd35ac1785b5372c9e4 Mon Sep 17 00:00:00 2001 From: MatejMa2ur Date: Sun, 19 Apr 2026 00:32:03 +0200 Subject: [PATCH 1/3] feat: add remove button in judging by team and make reassign judge list scrollable Co-Authored-By: Claude Sonnet 4.6 --- .../JudgingOverview/JudgingOverview.tsx | 27 +++++++++++-------- .../JudgingOverview/ReassignJudgeDialog.tsx | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx index 70144b8..b301f4e 100644 --- a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx +++ b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx @@ -325,17 +325,22 @@ const JudgingOverview = ({ hackathonId, data }: JudgingOverviewProps) => { {ja.hasVerdict ? "✓" : "pending"} {ja.type === "organizer" && ja.teamJudgingId && ( - j.name === ja.label) - ?.id ?? 0 - } - judges={judges.map((j) => ({ - id: j.id, - name: j.name, - }))} - /> + <> + j.name === ja.label) + ?.id ?? 0 + } + judges={judges.map((j) => ({ + id: j.id, + name: j.name, + }))} + /> + + )} ))} diff --git a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/ReassignJudgeDialog.tsx b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/ReassignJudgeDialog.tsx index dbcffad..74f0fde 100644 --- a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/ReassignJudgeDialog.tsx +++ b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/ReassignJudgeDialog.tsx @@ -86,7 +86,7 @@ const ReassignJudgeDialog = ({ - + {otherJudges.map((judge) => ( {judge.name} From d73d3bb7fb6ed3358b60c25654c8c6e3665d34b1 Mon Sep 17 00:00:00 2001 From: MatejMa2ur Date: Sun, 19 Apr 2026 00:45:11 +0200 Subject: [PATCH 2/3] fix: fix prettier formatting in JudgingOverview Co-Authored-By: Claude Sonnet 4.6 --- .../Judging/scenes/JudgingOverview/JudgingOverview.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx index b301f4e..04b471c 100644 --- a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx +++ b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx @@ -329,8 +329,9 @@ const JudgingOverview = ({ hackathonId, data }: JudgingOverviewProps) => { j.name === ja.label) - ?.id ?? 0 + judges.find( + (j) => j.name === ja.label + )?.id ?? 0 } judges={judges.map((j) => ({ id: j.id, From 196a08ab2038b5b263876b1c2086339da7a2a010 Mon Sep 17 00:00:00 2001 From: MatejMa2ur Date: Sun, 19 Apr 2026 01:40:27 +0200 Subject: [PATCH 3/3] feat: add remove button for sponsor assignments and enforce 1 sponsor per team Co-Authored-By: Claude Sonnet 4.6 --- .../DeleteSponsorJudgingButton.tsx | 44 +++++++++++++++++++ .../JudgingOverview/JudgingOverview.tsx | 9 ++++ .../dashboard/judging/createSponsorJudging.ts | 11 +++++ 3 files changed, 64 insertions(+) create mode 100644 src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/DeleteSponsorJudgingButton.tsx diff --git a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/DeleteSponsorJudgingButton.tsx b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/DeleteSponsorJudgingButton.tsx new file mode 100644 index 0000000..f342886 --- /dev/null +++ b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/DeleteSponsorJudgingButton.tsx @@ -0,0 +1,44 @@ +"use client"; + +import React, { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { X } from "lucide-react"; +import ConfirmationDialog from "@/components/common/ConfirmationDialog"; +import callServerAction from "@/services/helpers/server/callServerAction"; +import deleteSponsorJudging from "@/server/actions/dashboard/judging/deleteSponsorJudging"; + +type DeleteSponsorJudgingButtonProps = { + sponsorJudgingId: number; +}; + +const DeleteSponsorJudgingButton = ({ + sponsorJudgingId, +}: DeleteSponsorJudgingButtonProps) => { + const [error, setError] = useState(null); + + return ( + <> + { + if (!answer) return; + const res = await callServerAction(deleteSponsorJudging, { + sponsorJudgingId, + }); + if (!res.success) setError(res.message); + }} + > + + + {error &&

{error}

} + + ); +}; + +export default DeleteSponsorJudgingButton; diff --git a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx index 04b471c..2e887be 100644 --- a/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx +++ b/src/scenes/Dashboard/scenes/Judging/scenes/JudgingOverview/JudgingOverview.tsx @@ -9,6 +9,7 @@ import AutoAssignButton from "./AutoAssignButton"; import AutoAssignSponsorButton from "./AutoAssignSponsorButton"; import ReassignJudgeDialog from "./ReassignJudgeDialog"; import DeleteTeamJudgingButton from "./DeleteTeamJudgingButton"; +import DeleteSponsorJudgingButton from "./DeleteSponsorJudgingButton"; import ExternalJudgeManager from "./ExternalJudgeManager"; import AssignTeamDialog from "./AssignTeamDialog"; @@ -30,6 +31,7 @@ type TeamJudgingRow = { slotEnd: Date; hasVerdict: boolean; teamJudgingId?: number; + sponsorJudgingId?: number; type: "organizer" | "sponsor"; }[]; }; @@ -100,6 +102,7 @@ const JudgingOverview = ({ hackathonId, data }: JudgingOverviewProps) => { slotStart: slot.startTime, slotEnd: slot.endTime, hasVerdict: assignment.hasVerdict, + sponsorJudgingId: assignment.sponsorJudgingId, type: "sponsor", }); } @@ -323,6 +326,12 @@ const JudgingOverview = ({ hackathonId, data }: JudgingOverviewProps) => { {ja.label} {ja.hasVerdict ? "✓" : "pending"} + {ja.type === "sponsor" && + ja.sponsorJudgingId && ( + + )} {ja.type === "organizer" && ja.teamJudgingId && ( <> diff --git a/src/server/actions/dashboard/judging/createSponsorJudging.ts b/src/server/actions/dashboard/judging/createSponsorJudging.ts index 4bde742..8f82fcf 100644 --- a/src/server/actions/dashboard/judging/createSponsorJudging.ts +++ b/src/server/actions/dashboard/judging/createSponsorJudging.ts @@ -38,6 +38,17 @@ const createSponsorJudging = async ({ ); } + const existingForTeam = await prisma.sponsorJudging.findFirst({ + where: { sponsorId, teamId }, + select: { id: true }, + }); + + if (existingForTeam) { + throw new ExpectedServerActionError( + "Sponsor is already assigned to judge this team" + ); + } + await prisma.sponsorJudging.create({ data: { sponsorId, teamId, judgingSlotId }, });