Skip to content
1 change: 1 addition & 0 deletions amplify/data/resource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ export const handler: Schema["ScheduleTeamsAndJudges"]["functionHandler"] =
time: currTime.toISOString(),
roomId: roomIds[column],
zoomLink: "",
duration: presentationDuration,
},
},
}),
Expand Down
3 changes: 3 additions & 0 deletions amplify/graphql/API.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ export type TeamRoom = {
time: string;
updatedAt: string;
zoomLink: string;
duration?: number | null;
};

export type Room = {
Expand Down Expand Up @@ -493,6 +494,7 @@ export type CreateTeamRoomInput = {
teamId: string;
time: string;
zoomLink: string;
duration?: number | null;
};

export type ModelUserConditionInput = {
Expand Down Expand Up @@ -623,6 +625,7 @@ export type UpdateTeamRoomInput = {
teamId?: string | null;
time?: string | null;
zoomLink?: string | null;
duration?: number | null;
};

export type UpdateUserInput = {
Expand Down
1 change: 1 addition & 0 deletions amplify/graphql/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ export const createTeamRoom = /* GraphQL */ `mutation CreateTeamRoom(
time
updatedAt
zoomLink
duration
__typename
}
}
Expand Down
2 changes: 2 additions & 0 deletions amplify/graphql/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export const getTeamRoom = /* GraphQL */ `query GetTeamRoom($id: ID!) {
time
updatedAt
zoomLink
duration
__typename
}
}
Expand Down Expand Up @@ -427,6 +428,7 @@ export const listTeamRooms = /* GraphQL */ `query ListTeamRooms(
time
updatedAt
zoomLink
duration
__typename
}
nextToken
Expand Down
12 changes: 11 additions & 1 deletion src/app/admin/components/UsersTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
});
};
Expand Down
44 changes: 22 additions & 22 deletions src/app/judging/JudgingTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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 <KevinLoadingRing />;
}
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 = [
{
Expand Down
87 changes: 75 additions & 12 deletions src/app/judging/assigned-teams/page.tsx
Original file line number Diff line number Diff line change
@@ -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 <div className="p-6">Please sign in to see assigned teams.</div>;
if (roomLoading || teamsLoading)
return (
<div className="flex items-center justify-center pt-16">
<KevinLoadingRing />
</div>
);
if (!roomData)
return <div className="p-6">You have no room assigned yet.</div>;

return (
<div>
<h1> Put assinged teams here Assigned Teams</h1>
<ul>
{assignedTeams.map((team) => (
<li key={team.id}>{team.name}</li>
))}
</ul>
<div className="p-6">
<h1 className="mb-4 text-2xl font-semibold">
Your Teams: {roomData?.name ?? ""}
</h1>
{teamsForRoom && teamsForRoom.length > 0 ? (
<div className="grid w-full grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
{teamsForRoom.map((team: any) => (
<div
key={team.id}
className="flex flex-col justify-between rounded-lg border bg-white p-4 shadow-sm transition-shadow hover:shadow-lg"
>
<div>
<div className="text-lg font-bold text-gray-900">
<span>{team.name}</span>
</div>
<div className="mt-1 text-sm text-gray-500">
<span>Team ID: {team.id}</span>
</div>
</div>
</div>
))}
</div>
) : (
<div className="text-gray-600">
No teams assigned to your room yet. Check back later!
</div>
)}
</div>
);
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/LandingPage/HeroSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export default async function HeroSection() {
return <div>Hackathon hasn't been created yet</div>;
}

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 (
<div className="relative flex flex-col items-center justify-center md:px-8 md:py-16 lg:px-32">
Expand Down
5 changes: 4 additions & 1 deletion src/components/admin/Judging/JudgingSchedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}))
: [];
Expand Down
12 changes: 8 additions & 4 deletions src/components/admin/Judging/JudgingTimeline.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"use client";

import { Scheduler } from "@aldabil/react-scheduler";
import RedirectIcon from "../../RedirectIcon";

type JudgeRoom = {
roomName: string;
Expand Down Expand Up @@ -48,11 +49,14 @@ export default function JudgingTimeline({
deletable={false}
viewerExtraComponent={(fields, event) => {
return (
<p>
<a
href={event.zoomLink}
className="inline-flex flex-row items-center gap-1 text-dark-green hover:underline"
>
{/* Replace with actual zoom link not the room id */}
<span className="font-bold">Zoom Link:</span>{" "}
<a href={event.zoomLink}>{event.title}</a>
</p>
<span className="font-bold">Zoom Link</span>
<RedirectIcon />
</a>
);
}}
/>
Expand Down
26 changes: 18 additions & 8 deletions src/components/admin/Judging/RoomAssigner.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";

import { useState } from "react";
import { createZoomMeeting } from "@/app/zoom/actions";

Check warning on line 4 in src/components/admin/Judging/RoomAssigner.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint Scanning

'createZoomMeeting' is defined but never used

export default function RoomAssigner({
judgingScheduleMutation,
Expand All @@ -21,6 +21,8 @@
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);

const ZOOM_LINK = process.env.NEXT_PUBLIC_ZOOM_LINK;

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(e.target.value);
};
Expand Down Expand Up @@ -48,14 +50,22 @@
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) {

Check warning on line 68 in src/components/admin/Judging/RoomAssigner.tsx

View workflow job for this annotation

GitHub Actions / Run ESLint Scanning

'err' is defined but never used
setError("Failed to create Zoom meeting.");
} finally {
setLoading(false);
Expand All @@ -72,7 +82,7 @@
>
<div className="flex w-full flex-col gap-4 md:flex-row">
<div className="flex w-full flex-col gap-2 md:w-1/4">
<label htmlFor="numberOfRooms">Enter Number of Room:</label>
<label htmlFor="numberOfRooms">Enter Number of Rooms:</label>
<input
className="flex items-center justify-between rounded-lg border-2 border-awesome-purple bg-white p-4 font-bold text-black duration-100 hover:border-awesomer-purple active:border-awesome-purple active:text-black"
type="number"
Expand All @@ -82,7 +92,7 @@
/>
</div>
<div className="flex w-full flex-col gap-2 md:w-1/4">
<label htmlFor="duration">Enter Judging Duration:</label>
<label htmlFor="duration">Enter Duration (minutes):</label>
<input
id="duration"
className="flex items-center justify-between rounded-lg border-2 border-awesome-purple bg-white p-4 font-bold text-black duration-100 hover:border-awesomer-purple active:border-awesome-purple active:text-black"
Expand Down
Loading
Loading