Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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, 30, 0); // Month is 0-indexed → 10 = November
const eventEndDate = new Date(2025, 10, 9, 18, 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