diff --git a/amplify/data/resource.ts b/amplify/data/resource.ts
index a7bb7644..abc90963 100644
--- a/amplify/data/resource.ts
+++ b/amplify/data/resource.ts
@@ -131,6 +131,7 @@ const schema = a
id: a.id().required(),
time: a.datetime().required(),
zoomLink: a.string().required(),
+ duration: a.integer(),
teamId: a.id().required(),
roomId: a.id().required(),
team: a.belongsTo("Team", "teamId"),
diff --git a/amplify/function/BusinessLogic/ScheduleTeamsAndJudges/handler.ts b/amplify/function/BusinessLogic/ScheduleTeamsAndJudges/handler.ts
index 3d8ce54c..b8352b3b 100644
--- a/amplify/function/BusinessLogic/ScheduleTeamsAndJudges/handler.ts
+++ b/amplify/function/BusinessLogic/ScheduleTeamsAndJudges/handler.ts
@@ -118,6 +118,7 @@ export const handler: Schema["ScheduleTeamsAndJudges"]["functionHandler"] =
time: currTime.toISOString(),
roomId: roomIds[column],
zoomLink: "",
+ duration: presentationDuration,
},
},
}),
diff --git a/amplify/graphql/API.ts b/amplify/graphql/API.ts
index 394c22af..dda5abab 100644
--- a/amplify/graphql/API.ts
+++ b/amplify/graphql/API.ts
@@ -122,6 +122,7 @@ export type TeamRoom = {
time: string;
updatedAt: string;
zoomLink: string;
+ duration?: number | null;
};
export type Room = {
@@ -493,6 +494,7 @@ export type CreateTeamRoomInput = {
teamId: string;
time: string;
zoomLink: string;
+ duration?: number | null;
};
export type ModelUserConditionInput = {
@@ -623,6 +625,7 @@ export type UpdateTeamRoomInput = {
teamId?: string | null;
time?: string | null;
zoomLink?: string | null;
+ duration?: number | null;
};
export type UpdateUserInput = {
diff --git a/amplify/graphql/mutations.ts b/amplify/graphql/mutations.ts
index 79099b55..20ddf45d 100644
--- a/amplify/graphql/mutations.ts
+++ b/amplify/graphql/mutations.ts
@@ -342,6 +342,7 @@ export const createTeamRoom = /* GraphQL */ `mutation CreateTeamRoom(
time
updatedAt
zoomLink
+ duration
__typename
}
}
diff --git a/amplify/graphql/queries.ts b/amplify/graphql/queries.ts
index f6f4ce73..3348ac36 100644
--- a/amplify/graphql/queries.ts
+++ b/amplify/graphql/queries.ts
@@ -186,6 +186,7 @@ export const getTeamRoom = /* GraphQL */ `query GetTeamRoom($id: ID!) {
time
updatedAt
zoomLink
+ duration
__typename
}
}
@@ -427,6 +428,7 @@ export const listTeamRooms = /* GraphQL */ `query ListTeamRooms(
time
updatedAt
zoomLink
+ duration
__typename
}
nextToken
diff --git a/src/app/admin/components/UsersTable.tsx b/src/app/admin/components/UsersTable.tsx
index 23d1c2a6..5ad38e0f 100644
--- a/src/app/admin/components/UsersTable.tsx
+++ b/src/app/admin/components/UsersTable.tsx
@@ -19,11 +19,21 @@ export default function UsersTable({ users }: { users: User[] }) {
const deleteUser = async (id: Schema["User"]["deleteType"]) =>
client.models.User.delete(id);
const updateUser = async (updatedData: Schema["User"]["updateType"]) => {
+ if (updatedData.role) {
+ const roleUpdateResult = await client.mutations.AddUserToGroup({
+ userId: updatedData.id,
+ groupName: updatedData.role,
+ });
+
+ if (roleUpdateResult.errors) {
+ throw new Error("Failed to update user role in Cognito");
+ }
+ }
+
return client.models.User.update({
id: updatedData.id,
firstName: updatedData.firstName,
lastName: updatedData.lastName,
- role: updatedData.role,
teamId: updatedData.teamId,
});
};
diff --git a/src/app/judging/JudgingTable.tsx b/src/app/judging/JudgingTable.tsx
index 76715f62..4b4cc630 100644
--- a/src/app/judging/JudgingTable.tsx
+++ b/src/app/judging/JudgingTable.tsx
@@ -20,7 +20,6 @@ export default function JudgingTable({
}) {
const [selectedTeam, setSelectedTeamId] = useState("");
const [teamName, setTeamName] = useState("");
- const [teamsLeft, setTeamsLeft] = useState(0);
const { currentUser } = useUser();
const { data: roomData, isFetching: roomIsFetching } = useQuery({
@@ -51,30 +50,31 @@ export default function JudgingTable({
return teams;
},
});
- const isFetching = roomIsFetching && teamsForRoomIsFetching;
+
+ const { data: teamsLeft = 0, isFetching: teamsLeftIsFetching } = useQuery({
+ queryKey: ["TeamsLeftCount", teamsForRoomData, currentUser.username],
+ queryFn: async () => {
+ if (!teamsForRoomData) return 0;
+ const boolArray = await Promise.all(
+ teamsForRoomData.map(async (team) => {
+ const scores = await team?.scores();
+ return (
+ scores?.data.filter(
+ (score) => score.judgeId === currentUser.username,
+ ).length === 0
+ );
+ }),
+ );
+ return teamsForRoomData.filter((_, i) => boolArray[i]).length;
+ },
+ enabled: !!teamsForRoomData && !!currentUser.username,
+ });
+
+ const isFetching =
+ roomIsFetching || teamsForRoomIsFetching || teamsLeftIsFetching;
if (isFetching || !roomData || !teamsForRoomData) {
return ;
}
- async function getFilteredTeamsCount() {
- // https://medium.com/@debbs119/array-filter-and-array-map-with-async-functions-9636e1ae8d6e --> why it needs to map to a boolean array first
- if (!teamsForRoomData) {
- return;
- }
- const boolArray = await Promise.all(
- teamsForRoomData?.map(async (team) => {
- const scores = await team?.scores();
- return (
- scores?.data.filter((score) => score.judgeId === currentUser.username)
- .length === 0
- );
- }),
- );
- setTeamsLeft(
- teamsForRoomData?.filter((_, index) => boolArray[index]).length,
- );
- }
-
- getFilteredTeamsCount();
const panelData = [
{
diff --git a/src/app/judging/assigned-teams/page.tsx b/src/app/judging/assigned-teams/page.tsx
index f3f80d96..d43adf34 100644
--- a/src/app/judging/assigned-teams/page.tsx
+++ b/src/app/judging/assigned-teams/page.tsx
@@ -1,18 +1,81 @@
+"use client";
+
+import React from "react";
+import { client } from "@/app/QueryProvider";
+import { useUser } from "@/components/contexts/UserContext";
+import KevinLoadingRing from "@/components/KevinLoadingRing";
+import { useQuery } from "@tanstack/react-query";
+
const AssignedTeamsPage = () => {
- const assignedTeams = [
- { id: 1, name: "Team Alpha" },
- { id: 2, name: "Team Beta" },
- { id: 3, name: "Team Gamma" },
- ];
+ const { currentUser } = useUser();
+
+ const { data: roomData, isLoading: roomLoading } = useQuery({
+ queryKey: ["RoomForJudge", currentUser?.JUDGE_roomId],
+ queryFn: async () => {
+ if (!currentUser?.JUDGE_roomId)
+ throw new Error("No room assigned to judge");
+ const { data, errors } = await client.models.Room.get({
+ id: currentUser.JUDGE_roomId,
+ });
+ if (errors) throw new Error(errors[0]?.message || "Failed to load room");
+ return data;
+ },
+ enabled: !!currentUser?.JUDGE_roomId,
+ });
+
+ const { data: teamsForRoom, isLoading: teamsLoading } = useQuery({
+ queryKey: ["TeamsForRoom", roomData?.id],
+ queryFn: async () => {
+ if (!roomData) return [];
+ const teamRooms = (await roomData.teamRoom())?.data;
+ if (!teamRooms) return [];
+ const teams = await Promise.all(
+ teamRooms.map(async (tr) => (await tr.team()).data),
+ );
+ return teams;
+ },
+ enabled: !!roomData,
+ });
+
+ if (!currentUser)
+ return
Please sign in to see assigned teams.
;
+ if (roomLoading || teamsLoading)
+ return (
+
+
+
+ );
+ if (!roomData)
+ return You have no room assigned yet.
;
return (
-
-
Put assinged teams here Assigned Teams
-
- {assignedTeams.map((team) => (
- - {team.name}
- ))}
-
+
+
+ Your Teams: {roomData?.name ?? ""}
+
+ {teamsForRoom && teamsForRoom.length > 0 ? (
+
+ {teamsForRoom.map((team: any) => (
+
+
+
+ {team.name}
+
+
+ Team ID: {team.id}
+
+
+
+ ))}
+
+ ) : (
+
+ No teams assigned to your room yet. Check back later!
+
+ )}
);
};
diff --git a/src/components/LandingPage/HeroSection.tsx b/src/components/LandingPage/HeroSection.tsx
index e9bdb6e8..3ff619eb 100644
--- a/src/components/LandingPage/HeroSection.tsx
+++ b/src/components/LandingPage/HeroSection.tsx
@@ -19,8 +19,8 @@ export default async function HeroSection() {
return
Hackathon hasn't been created yet
;
}
- const eventStartDate = new Date(hackathonData[0].startDate);
- const eventEndDate = new Date(hackathonData[0].endDate);
+ const eventStartDate = new Date(2025, 10, 8, 9, 0, 0); // Month is 0-indexed → 10 = November
+ const eventEndDate = new Date(2025, 10, 9, 17, 0, 0); // Example: Sunday 5 PM
return (
diff --git a/src/components/admin/Judging/JudgingSchedule.tsx b/src/components/admin/Judging/JudgingSchedule.tsx
index b97e81e7..8cfe9986 100644
--- a/src/components/admin/Judging/JudgingSchedule.tsx
+++ b/src/components/admin/Judging/JudgingSchedule.tsx
@@ -168,7 +168,10 @@ export default function JudgingSchedule() {
.join(", ") || "No Team Name",
room_id: teamRoom.roomId,
start: new Date(teamRoom.time),
- end: new Date(new Date(teamRoom.time).getTime() + 15 * 60 * 1000),
+ end: new Date(
+ new Date(teamRoom.time).getTime() +
+ (teamRoom.duration ?? 10) * 60 * 1000,
+ ),
zoomLink: teamRoom.zoomLink,
}))
: [];
diff --git a/src/components/admin/Judging/JudgingTimeline.tsx b/src/components/admin/Judging/JudgingTimeline.tsx
index 7bd8f221..28ea0c12 100644
--- a/src/components/admin/Judging/JudgingTimeline.tsx
+++ b/src/components/admin/Judging/JudgingTimeline.tsx
@@ -1,6 +1,7 @@
"use client";
import { Scheduler } from "@aldabil/react-scheduler";
+import RedirectIcon from "../../RedirectIcon";
type JudgeRoom = {
roomName: string;
@@ -48,11 +49,14 @@ export default function JudgingTimeline({
deletable={false}
viewerExtraComponent={(fields, event) => {
return (
-
+
{/* Replace with actual zoom link not the room id */}
- Zoom Link:{" "}
- {event.title}
-
+
Zoom Link
+
+
);
}}
/>
diff --git a/src/components/admin/Judging/RoomAssigner.tsx b/src/components/admin/Judging/RoomAssigner.tsx
index d2da6fda..a87dd22a 100644
--- a/src/components/admin/Judging/RoomAssigner.tsx
+++ b/src/components/admin/Judging/RoomAssigner.tsx
@@ -21,6 +21,8 @@ export default function RoomAssigner({
const [loading, setLoading] = useState
(false);
const [error, setError] = useState(null);
+ const ZOOM_LINK = process.env.NEXT_PUBLIC_ZOOM_LINK;
+
const handleInputChange = (e: React.ChangeEvent) => {
setInputValue(e.target.value);
};
@@ -48,13 +50,21 @@ export default function RoomAssigner({
presentationDuration: Number(duration),
});
- const meetingData = await createZoomMeeting(
- formattedDate,
- Number(duration),
- );
+ // dynamically create zoom links
+ // const meetingData = await createZoomMeeting(
+ // formattedDate,
+ // Number(duration),
+ // );
+
+ // setMeetingLink(meetingData.join_url);
+ // updateTeamRoomsWithZoomLink();
+
+ // temporary hardcoded zoom link
+ if (!ZOOM_LINK) {
+ throw new Error("Zoom link missing in .env.");
+ }
- setMeetingLink(meetingData.join_url);
- updateTeamRoomsWithZoomLink(meetingData.join_url);
+ updateTeamRoomsWithZoomLink(ZOOM_LINK);
} catch (err) {
setError("Failed to create Zoom meeting.");
} finally {
@@ -72,7 +82,7 @@ export default function RoomAssigner({
>
-
+
-
+
{teamName}
- {Object.keys(components).map((componentId) => {
- return (
-
- {components[componentId]}
- |
- );
- })}
+ {scoringMetrics
+ .filter((metric) => !metric.isSidepot)
+ .map((metric) => {
+ return (
+
+ {components[metric.id] || 0}
+ |
+ );
+ })}
{total}
|
+ {scoringMetrics
+ .filter((metric) => metric.isSidepot)
+ .map((metric) => {
+ return (
+
+ {components[metric.id] || 0}
+ |
+ );
+ })}
);
}
@@ -101,7 +117,11 @@ export default function RankingTable({
Number(score.score[scoreComponentId])
: score.score[scoreComponentId];
- return total + Number(score.score[scoreComponentId]);
+ // Only add to total if it's not a sidepot
+ if (!metric.isSidepot) {
+ return total + Number(score.score[scoreComponentId]);
+ }
+ return total;
}, 0);
acc[score.teamId].total += teamScore;
@@ -145,24 +165,25 @@ export default function RankingTable({
Team
|
- {scoringMetrics.map((metric) => {
- return (
-
-
- {metric.friendlyName}
- {metric.isSidepot ? " (Sidepot)" : null}
-
-
- |
- );
- })}
+ {scoringMetrics
+ .filter((metric) => !metric.isSidepot)
+ .map((metric) => {
+ return (
+
+
+ {metric.friendlyName}
+
+
+ |
+ );
+ })}
Total
@@ -176,6 +197,25 @@ export default function RankingTable({
|
+ {scoringMetrics
+ .filter((metric) => metric.isSidepot)
+ .map((metric) => {
+ return (
+
+
+ {metric.friendlyName} (Sidepot)
+
+
+ |
+ );
+ })}
@@ -185,6 +225,7 @@ export default function RankingTable({
teamName={computedScores[teamId].name}
components={computedScores[teamId].components}
total={computedScores[teamId].total}
+ scoringMetrics={scoringMetrics}
key={index}
index={index}
/>
diff --git a/src/components/judging/Schedule/schedule.tsx b/src/components/judging/Schedule/schedule.tsx
index d7666d9d..396e986f 100644
--- a/src/components/judging/Schedule/schedule.tsx
+++ b/src/components/judging/Schedule/schedule.tsx
@@ -4,6 +4,7 @@ import { generateClient } from "aws-amplify/api";
import { useState } from "react";
import { type Schema } from "@/amplify/data/resource";
import JudgingTimeline from "@/components/admin/Judging/JudgingTimeline";
+import KevinLoadingRing from "@/components/KevinLoadingRing";
import { useQuery } from "@tanstack/react-query";
const client = generateClient();
@@ -94,62 +95,29 @@ export default function JudgingSchedule() {
.join(", ") || "No Team Name",
room_id: teamRoom.roomId,
start: new Date(teamRoom.time),
- end: new Date(new Date(teamRoom.time).getTime() + 15 * 60 * 1000),
+ end: new Date(
+ new Date(teamRoom.time).getTime() +
+ (teamRoom.duration ?? 10) * 60 * 1000,
+ ),
zoomLink: teamRoom.zoomLink,
}))
: [];
- // State to manage the filter (all teams or assigned teams)
- const [filter, setFilter] = useState<"all" | "assigned">("all");
-
- // Filtered events based on the selected filter
- const filteredEvents =
- filter === "all"
- ? judgingEvents
- : judgingEvents.filter((event) =>
- judgeData?.some((judge) => judge.JUDGE_roomId === event.room_id),
- );
-
return isLoading ? (
-
- Loading schedule...
+
+
) : (
- {/* Filter Buttons */}
-
-
+
Judging Schedule
- {/* Schedule Display */}
- {filteredEvents.length > 0 ? (
-
- ) : (
-
Schedule not made yet
- )}
+
);
diff --git a/src/components/teamRegistration/TeamConfirmation.tsx b/src/components/teamRegistration/TeamConfirmation.tsx
index e44bb4bc..14093447 100644
--- a/src/components/teamRegistration/TeamConfirmation.tsx
+++ b/src/components/teamRegistration/TeamConfirmation.tsx
@@ -23,8 +23,8 @@ export default async function TeamConfirmation({
return
Hackathon hasn't been created yet
;
}
- const eventStartDate = new Date(hackathonData[0].startDate);
- const eventEndDate = new Date(hackathonData[0].endDate);
+ const eventStartDate = new Date(2025, 10, 8, 9, 0, 0); // Month is 0-indexed → 10 = November
+ const eventEndDate = new Date(2025, 10, 9, 17, 0, 0); // Example: Sunday 5 PM
return (
<>