No judging left.
;
+ }
+
+ const judging = judgings[judgingIndex];
+
+ const onVerdictSubmit = async (
+ values: { voteParameterId: number; value: number }[]
+ ) => {
+ const verdict = values
+ .map(({ voteParameterId, value }) => {
+ const voteParameter = voteParametersJudging.find(
+ (vp) => vp.id === voteParameterId
+ );
+ if (!voteParameter) {
+ throw new Error("Vote parameter not found");
+ }
+ return `${voteParameter.name}-${value}`;
+ })
+ .join(";");
+
+ const res = await callServerAction(addSponsorVerdict, {
+ sponsorJudgingId: judging.id,
+ judgingVerdict: verdict,
+ });
+
+ if (res.success) {
+ if (!changeJudging) {
+ setJudgingIndex(judgingIndex + 1);
+ toast({
+ title: "Verdict saved",
+ description: "The verdict has been saved.",
+ });
+ } else {
+ toast({
+ title: "Verdict changed",
+ description: "The verdict has been changed.",
+ });
+ }
+ setChangeJudging(false);
+ }
+ };
+
+ return (
+
+
+
{judgingIndex + 1}. Judging
+
+ Time: {dateToTimeString(judging.startTime)} -{" "}
+ {dateToTimeString(judging.endTime)}
+
+
+ Team: {judging.team.name}
+
+ {judging.team.tableCode && (
+
+ Table: {judging.team.tableCode}
+
+ )}
+
+ Challenges: {judging.team.challenges.join(", ")}
+
+ {judging.judgingVerdict && !changeJudging ? (
+
+
+ {judging.judgingVerdict.split(";").map((value) => (
+
+ {value.split("-")[0]}: {value.split("-")[1]}
+
+ ))}
+
+
+
+ ) : (
+
+ )}
+
+ {judgingIndex > 0 && (
+
+ )}
+
+ {judgingIndex < judgings.length - 1 && (
+
+ )}
+
+
+ );
+};
+
+export default SponsorJudgingSwitcher;
diff --git a/src/server/actions/dashboard/judging/autoAssignJudging.ts b/src/server/actions/dashboard/judging/autoAssignJudging.ts
new file mode 100644
index 0000000..312c2f0
--- /dev/null
+++ b/src/server/actions/dashboard/judging/autoAssignJudging.ts
@@ -0,0 +1,124 @@
+"use server";
+
+import { prisma } from "@/services/prisma";
+import requireAdminSession from "@/server/services/helpers/auth/requireAdminSession";
+import { revalidatePath } from "next/cache";
+import { ExpectedServerActionError } from "@/services/types/serverErrors";
+
+const autoAssignJudging = async (hackathonId: number) => {
+ await requireAdminSession();
+
+ const [slots, organizers, teams, existingAssignments] = await Promise.all([
+ prisma.judgingSlot.findMany({
+ where: { hackathonId },
+ orderBy: { startTime: "asc" },
+ }),
+ prisma.organizer.findMany({
+ select: { id: true },
+ }),
+ prisma.team.findMany({
+ where: {
+ members: { some: { hackathonId } },
+ table: { hackathonId },
+ },
+ select: { id: true },
+ }),
+ prisma.teamJudging.findMany({
+ where: { judgingSlot: { hackathonId } },
+ select: { judgingSlotId: true, organizerId: true, teamId: true },
+ }),
+ ]);
+
+ if (slots.length === 0) {
+ throw new ExpectedServerActionError(
+ "No judging slots found for this hackathon"
+ );
+ }
+ if (organizers.length === 0) {
+ throw new ExpectedServerActionError("No judges found");
+ }
+ if (teams.length === 0) {
+ throw new ExpectedServerActionError("No teams with tables found");
+ }
+
+ // Track state with O(1) lookups
+ // judgeSlots: judge already assigned in a given slot
+ const judgeSlots = new Map