From 56aa78ea39c8471774561ebab4ab81a31b6b9234 Mon Sep 17 00:00:00 2001 From: Ideen <48538139+ideen1@users.noreply.github.com> Date: Sun, 10 Nov 2024 11:24:28 -0700 Subject: [PATCH] Merge to prod (#160) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Hanna <144185720+hannagracec@users.noreply.github.com> Co-authored-by: Burton Jong <108391733+burtonjong@users.noreply.github.com> Co-authored-by: burtonjong Co-authored-by: Justin Pham <113923596+justin-phxm@users.noreply.github.com> Co-authored-by: hannagracec Co-authored-by: Natalie --- amplify/data/resource.ts | 7 +- src/app/globals.css | 26 ++++ src/app/judging/JudgingDashboard.tsx | 14 +- src/app/judging/JudgingTable.tsx | 122 +++++++----------- src/app/judging/page.tsx | 2 +- src/app/page.tsx | 2 +- src/components/LandingPage/AboutEventTile.tsx | 11 +- .../LandingPage/HeroSectionTile.tsx | 20 +-- .../LandingPage/JudgingCriteria.tsx | 4 +- src/components/UserProfile/TeamForm.tsx | 49 +++++-- src/components/UserProfile/TeamProfile.tsx | 23 +--- .../admin/Judging/JudgingTimeline.tsx | 6 +- src/components/contexts/UserContext.tsx | 1 + src/components/judging/ScoresTable.tsx | 120 +++++++++-------- src/components/judging/StatsPanel.tsx | 21 ++- 15 files changed, 220 insertions(+), 208 deletions(-) diff --git a/amplify/data/resource.ts b/amplify/data/resource.ts index dcfdc4d1..62834945 100644 --- a/amplify/data/resource.ts +++ b/amplify/data/resource.ts @@ -25,7 +25,12 @@ const schema = a allow.ownerDefinedIn("profileOwner").to(["read", "create"]), allow.groups(["Admin"]).to(["read", "update", "create"]), ]), - email: a.string(), + email: a + .string() + .authorization((allow) => [ + allow.ownerDefinedIn("profileOwner").to(["read", "create"]), + allow.groups(["Admin"]).to(["read", "create"]), + ]), institution: a.string(), completedRegistration: a.boolean(), allergies: a.string(), diff --git a/src/app/globals.css b/src/app/globals.css index 35bde7ca..e129f51b 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -32,6 +32,32 @@ body { rgb(var(--background-start-rgb)); } +@media (max-width: 768px) { + .text-shadow-outline { + text-shadow: + -2px -2px 0 #7055fd, + 2px -2px 0 #7055fd, + -2px 2px 0 #7055fd, + 2px 2px 0 #7055fd, + -2px -2px 0 #7055fd, + 2px -2px 0 #7055fd, + -2px 2px 0 #7055fd, + 2px 2px 0 #7055fd; + } +} + +.text-shadow-title { + text-shadow: + -2px -2px 0 #7055fd, + 2px -2px 0 #7055fd, + -2px 2px 0 #7055fd, + 2px 2px 0 #7055fd, + -2px -2px 0 #7055fd, + 2px -2px 0 #7055fd, + -2px 2px 0 #7055fd, + 2px 2px 0 #7055fd; +} + .lds-ring, .lds-ring div { box-sizing: border-box; diff --git a/src/app/judging/JudgingDashboard.tsx b/src/app/judging/JudgingDashboard.tsx index d0edfc1f..4209a87d 100644 --- a/src/app/judging/JudgingDashboard.tsx +++ b/src/app/judging/JudgingDashboard.tsx @@ -12,14 +12,10 @@ export default async function JudgingDashboard() { }; return ( - <> -
-
- -

Assigned Teams

- -
-
- +
+ +

Assigned Teams

+ +
); } diff --git a/src/app/judging/JudgingTable.tsx b/src/app/judging/JudgingTable.tsx index 3b5e8e03..ccfcdafd 100644 --- a/src/app/judging/JudgingTable.tsx +++ b/src/app/judging/JudgingTable.tsx @@ -1,6 +1,7 @@ "use client"; -import { useMemo, useState } from "react"; +import { useState } from "react"; +import Skeleton from "react-loading-skeleton"; import type { Schema } from "@/amplify/data/resource"; import LoadingRing from "@/components/LoadingRing"; @@ -48,36 +49,34 @@ export default function JudgingTable({ return teams; }, }); - if ( - roomIsFetching || - teamsForRoomIsFetching || - !roomData || - !teamsForRoomData - ) { - return
Loading...
; + const isFetching = roomIsFetching || teamsForRoomIsFetching; + if (isFetching || !roomData || !teamsForRoomData) { + return ( +
+ +
+ ); } - const panelData = useMemo(() => { - return [ - { - icon: "/svgs/judging/team_icon.svg", - alt: "Teams assigned icon", - stat: teamsForRoomData.length, - text: `Teams Assigned to ${roomData.name}`, - }, - { - icon: "/svgs/judging/teams_left.svg", - alt: "Teams left icon", - stat: teamsForRoomData.filter( - async (team) => - (await team?.scores())?.data.filter( - (score) => score.judgeId === currentUser.username, - ).length === 0, - ).length, - text: "Teams Left To Score", - }, - ]; - }, [roomData, teamsForRoomData]); + const panelData = [ + { + icon: "/svgs/judging/team_icon.svg", + alt: "Teams assigned icon", + stat: teamsForRoomData.length, + text: `Teams Assigned to ${roomData.name}`, + }, + { + icon: "/svgs/judging/teams_left.svg", + alt: "Teams left icon", + stat: teamsForRoomData.filter( + async (team) => + (await team?.scores())?.data.filter( + (score) => score.judgeId === currentUser.username, + ).length === 0, + ).length, + text: "Teams Left To Score", + }, + ]; const handleCreateScoreClick = (teamId: string) => { setSelectedTeamId(teamId); }; @@ -89,57 +88,32 @@ export default function JudgingTable({ setSelectedTeamId(""); }; - const isFetching = roomIsFetching || teamsForRoomIsFetching; - - const tableHeaders = [ - { columnHeader: "Team Name", className: "w-1/3 rounded-tl-lg" }, - ...hackathonData.scoringComponents.map((component) => ({ - columnHeader: component.friendlyName, - className: "w-fit", - })), - ...hackathonData.scoringSidepots.map((component) => ({ - columnHeader: ( -
-

Sidepot:

- {component.friendlyName} -
- ), - className: "w-fit bg-pastel-pink", - })), - ]; return isFetching ? ( -
+
) : ( -
-
-
+ <> +
+
{panelData.map((item, index) => ( -
- -
+ ))}
-
- -
+
{selectedTeam !== "" && ( )} -
+ ); } diff --git a/src/app/judging/page.tsx b/src/app/judging/page.tsx index ee36f878..5ee489b1 100644 --- a/src/app/judging/page.tsx +++ b/src/app/judging/page.tsx @@ -19,7 +19,7 @@ export const metadata: Metadata = { }; export default function Judging() { return ( -
+
); diff --git a/src/app/page.tsx b/src/app/page.tsx index c8d69b47..6115fa8b 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -10,7 +10,7 @@ import { enableLandingPage } from "@/featureFlags"; export const revalidate = 600; const Home = () => { return ( -
+
{enableLandingPage ? ( ) : ( diff --git a/src/components/LandingPage/AboutEventTile.tsx b/src/components/LandingPage/AboutEventTile.tsx index 9fa74e48..32d03c87 100644 --- a/src/components/LandingPage/AboutEventTile.tsx +++ b/src/components/LandingPage/AboutEventTile.tsx @@ -3,15 +3,16 @@ import type { ReactNode } from "react"; import { fetchContent } from "@/app/actions"; -const EVENT_DETAILS_SECTION_STYLES = "flex flex-col items-center bg-white"; +const EVENT_DETAILS_SECTION_STYLES = + "flex w-full flex-col items-center bg-white"; const EVENT_DETAILS_CONTENT_STYLES = - "bg-pastel-pink border-4 border-dark-pink rounded-3xl my-4 lg:my-8 flex md:flex md:justify-center md:max-w-[1100px] md:shadow-[15px_15px_0px_0px_#FF4D6F]"; + "bg-pastel-pink border-4 border-dark-pink rounded-3xl mt-4 mb-8 xl:mt-8 xl:mb-12 flex flex-col xl:flex-row w-4/5 shadow-[15px_15px_0px_0px_#FF4D6F]"; const EVENT_IMAGE_CONTAINER_STYLES = - "bg-blackish rounded-t-20 border-b-4 border-dark-pink w-72 h-64 md:rounded-tr-none md:rounded-l-3xl md:border-b-0 md:border-r-4 md:h-[370px] md:w-[40vw]"; + "bg-blackish border-b-4 border-dark-pink size-full xl:size-1/2 rounded-t-2xl xl:rounded-tr-none xl:rounded-l-2xl xl:border-b-0 xl:border-r-4 "; const EVENT_IMAGE_STYLES = - "w-full h-full object-cover md:rounded-l-2xl md:rounded-tl-2xl md:rounded-t-none rounded-t-2xl"; + "w-full h-full object-cover rounded-bl-none rounded-t-2xl xl:rounded-tr-none xl:rounded-l-2xl"; const EVENT_DETAILS_CONTAINER_STYLES = - "flex items-center w-72 h-[370px] rounded-b-20 md:w-[50vw] md:rounded-bl-none md:rounded-r-2xl"; + "flex items-center w-full xl:w-1/2 rounded-b-20 md:rounded-bl-none md:rounded-r-2xl"; const EVENT_DETAIL_STYLES = "flex items-center ml-10"; const EVENT_DETAIL_TITLE_STYLES = "text-lg text-blackish font-extrabold leading-tight"; diff --git a/src/components/LandingPage/HeroSectionTile.tsx b/src/components/LandingPage/HeroSectionTile.tsx index 03e2fe18..23287c55 100644 --- a/src/components/LandingPage/HeroSectionTile.tsx +++ b/src/components/LandingPage/HeroSectionTile.tsx @@ -2,19 +2,6 @@ import type { HackathonDetails } from "@/app/contentfulTypes"; import HeroCallToAction from "./HeroCallToAction"; -const HERO_HEADER_STYLE = { - textShadow: ` - -2px -2px 0 #7055FD, - 2px -2px 0 #7055FD, - -2px 2px 0 #7055FD, - 2px 2px 0 #7055FD, - -2px -2px 0 #7055FD, - 2px -2px 0 #7055FD, - -2px 2px 0 #7055FD, - 2px 2px 0 #7055FD - `, -}; - const HeroSectionTile = ({ hackathonDetails, }: { @@ -26,13 +13,10 @@ const HeroSectionTile = ({ return (
-

+

{eventName} {" " + eventYear}

- + {eventBlurb} diff --git a/src/components/LandingPage/JudgingCriteria.tsx b/src/components/LandingPage/JudgingCriteria.tsx index 4029a871..4f56c9d7 100644 --- a/src/components/LandingPage/JudgingCriteria.tsx +++ b/src/components/LandingPage/JudgingCriteria.tsx @@ -1,10 +1,10 @@ import Image from "next/image"; const judgingCriteriaStyles = - "relative flex -mt-5 justify-between bg-[#BAFBE4] py-20 px-10 md:px-24 lg:px-40 drop-shadow-lg md:drop-shadow-none"; + "relative flex -mt-5 justify-between bg-[#BAFBE4] py-20 px-[5%] md:px-24 lg:px-40 drop-shadow-lg md:drop-shadow-none"; const itemStyles = - "flex justify-start p-4 lg:px-10 lg:text-[1.0rem] items-start"; + "flex justify-start p-4 lg:px-6 lg:text-[1.0rem] items-start"; const checkMarkSvg = "/svgs/landingPage/check_mark_bkg.svg"; diff --git a/src/components/UserProfile/TeamForm.tsx b/src/components/UserProfile/TeamForm.tsx index c35fdfc2..56c3b55d 100644 --- a/src/components/UserProfile/TeamForm.tsx +++ b/src/components/UserProfile/TeamForm.tsx @@ -1,4 +1,9 @@ +"use client"; + +import { generateClient } from "aws-amplify/api"; + import { type Schema } from "@/amplify/data/resource"; +import { useQuery } from "@tanstack/react-query"; const INPUT_STYLES = "rounded-full border-4 placeholder-black border-white bg-[#FFFFFF] bg-white/30 ps-3 py-2 my-2 text-sm md:text-md backdrop-opacity-30"; @@ -17,7 +22,23 @@ export default function TeamForm({ data, teamMutation }: TeamFormProp) { teamMutation.mutate(data); }; + const client = generateClient(); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { data: teamData, isFetching } = useQuery({ + initialData: null, + initialDataUpdatedAt: 0, + queryKey: ["TeamWithMembers"], + queryFn: async () => { + const { data: teamWithMembers } = await client.models.Team.get( + { id: data.id }, + { selectionSet: ["id", "members.*"] }, + ); + + return teamWithMembers; + }, + enabled: !!data, + }); return ( <> @@ -40,16 +61,24 @@ export default function TeamForm({ data, teamMutation }: TeamFormProp) { />
- {Array.isArray(data.members) && - data.members.map((member: Schema["User"]["type"]) => ( - - ))} + {isFetching ? ( +

Loading...

+ ) : ( + <> + {Array.isArray(teamData?.members) && + teamData?.members.map( + (member: Partial) => ( + + ), + )} + + )}
diff --git a/src/components/UserProfile/TeamProfile.tsx b/src/components/UserProfile/TeamProfile.tsx index 36c10e2b..a50544dd 100644 --- a/src/components/UserProfile/TeamProfile.tsx +++ b/src/components/UserProfile/TeamProfile.tsx @@ -16,25 +16,13 @@ const TEAM_INSTRUCTION_STYLES = const TeamProfile = () => { const queryClient = useQueryClient(); - const userId = useUser().currentUser.username as string; + const userTeamId = useUser().currentUser.teamId as string; const { data, isFetching } = useQuery({ initialData: {} as Schema["Team"]["type"], initialDataUpdatedAt: 0, - queryKey: ["Team", userId], + queryKey: ["Team", userTeamId], queryFn: async () => { - const userResponse = await client.models.User.get({ - id: userId, - }); - - if (userResponse.errors) throw new Error(userResponse.errors[0].message); - - const userTeamId = userResponse.data?.teamId as string; - - if (!userTeamId) { - return {} as Schema["Team"]["type"]; - } - const teamResponse = await client.models.Team.get({ id: userTeamId, }); @@ -43,12 +31,13 @@ const TeamProfile = () => { return teamResponse.data; }, + enabled: !!userTeamId, }); const teamMutation = useMutation({ mutationFn: async () => { try { - await client.models.User.update({ id: userId, teamId: null }); + await client.models.User.update({ id: userTeamId, teamId: null }); } catch (error) { console.error("Error updating ids", error); throw error; @@ -56,14 +45,14 @@ const TeamProfile = () => { }, onSuccess: () => { queryClient.invalidateQueries({ - queryKey: ["Team", userId], + queryKey: ["Team", userTeamId], }); }, }); return ( <> - {isFetching ? ( + {isFetching || !userTeamId ? (
diff --git a/src/components/admin/Judging/JudgingTimeline.tsx b/src/components/admin/Judging/JudgingTimeline.tsx index 58d156da..7bd8f221 100644 --- a/src/components/admin/Judging/JudgingTimeline.tsx +++ b/src/components/admin/Judging/JudgingTimeline.tsx @@ -41,9 +41,9 @@ export default function JudgingTimeline({ colorField: "color", }} day={{ - startHour: 15, // will have to be edited when we know what times to capture - endHour: 18, - step: 15, + startHour: 12, // will have to be edited when we know what times to capture + endHour: 17, + step: 10, }} deletable={false} viewerExtraComponent={(fields, event) => { diff --git a/src/components/contexts/UserContext.tsx b/src/components/contexts/UserContext.tsx index 6d3d0c48..19e54598 100644 --- a/src/components/contexts/UserContext.tsx +++ b/src/components/contexts/UserContext.tsx @@ -96,6 +96,7 @@ export function UserContextProvider({ children }: Props) { populated: true, completedProfile: response.data?.completedRegistration ?? false, email: response.data?.email ?? "", + teamId: response.data?.teamId ?? "", firstName: response.data?.firstName ?? "", lastName: response.data?.lastName ?? "", JUDGE_roomId: response.data?.JUDGE_roomId, diff --git a/src/components/judging/ScoresTable.tsx b/src/components/judging/ScoresTable.tsx index d0ea94a0..fc046b34 100644 --- a/src/components/judging/ScoresTable.tsx +++ b/src/components/judging/ScoresTable.tsx @@ -1,22 +1,18 @@ import { generateClient } from "aws-amplify/api"; import Image from "next/image"; import { useState } from "react"; +import { twMerge } from "tailwind-merge"; import { type Schema } from "@/amplify/data/resource"; import { useQuery } from "@tanstack/react-query"; +import Card from "../Dashboard/Card"; import { useUser } from "../contexts/UserContext"; import { type ScoreObject } from "./ModalPopup"; const edit_icon = "/svgs/judging/edit_icon.svg"; const filter_icon = "/svgs/judging/filter_arrows.svg"; -const JUDGE_TABLE_SECTION_STYLES = - "h-full rounded-lg bg-white p-6 drop-shadow-md"; - -const JUDGE_TABLE_CONTENT_STYLES = - "w-full border-separate border-spacing-x-0.5"; -const JUDGE_TABLE_HEADER_CELL_STLYES = "text-white text-xl font-medium py-4"; const JUDGE_TABLE_CELL_STYLES = "text-center text-lg py-4"; const SCORE_BUTTON_STYLES = "rounded-full border-2 px-2 py-1 text-sm font-medium"; @@ -39,33 +35,50 @@ const COLOR_SCHEMES = { const client = generateClient(); interface JudgingTableProps { - tableHeaders: Array<{ - columnHeader: string | JSX.Element; - className: string; - }>; tableData: Schema["Team"]["type"][]; onCreateScoreClick: (teamName: string) => void; onEditScoreClick: (teamName: string) => void; colorScheme: "pink" | "purple"; entriesPerPage: number; + hackathonData: Pick< + Schema["Hackathon"]["type"], + "scoringComponents" | "scoringSidepots" + >; } -const JudgingTable = (props: JudgingTableProps) => { +export default function JudgingTable(props: JudgingTableProps) { const { currentUser } = useUser(); const { - tableHeaders, tableData, onCreateScoreClick, onEditScoreClick, colorScheme, entriesPerPage, + hackathonData, } = props; + const [currentPage, setCurrentPage] = useState(1); const [sortedData, setSortedData] = useState(tableData); const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc"); const entries_per_page = entriesPerPage; + const tableHeaders = [ + { columnHeader: "Team Name", className: "px-6 rounded-tl-lg" }, + ...hackathonData.scoringComponents.map((component) => ({ + columnHeader: component.friendlyName, + className: "w-fit", + })), + ...hackathonData.scoringSidepots.map((component) => ({ + columnHeader: ( +
+

Sidepot:

+ {component.friendlyName} +
+ ), + className: "w-fit bg-pastel-pink", + })), + ]; const handleNextPage = () => { setCurrentPage((prevPage) => Math.min(prevPage + 1, Math.ceil(tableData.length / entries_per_page)), @@ -101,22 +114,26 @@ const JudgingTable = (props: JudgingTableProps) => { const colorStyles = COLOR_SCHEMES[colorScheme]; return ( -
-
- + +
+
{tableHeaders.map((header, index) => ( ))} + className={` rounded-tr-lg p-12 ${colorStyles.headerCellBg}`} + /> @@ -130,7 +147,6 @@ const JudgingTable = (props: JudgingTableProps) => { teamId: team.id, }); if (errors) throw Error(errors[0].message); - console.log(data); return data; } catch (error) { console.error(error); @@ -187,44 +203,36 @@ const JudgingTable = (props: JudgingTableProps) => { })}
{header.columnHeader}
-
-
+
+ +
+ + -
- - -
-
+ ); -}; - -export default JudgingTable; +} diff --git a/src/components/judging/StatsPanel.tsx b/src/components/judging/StatsPanel.tsx index 6fbfba85..95786b54 100644 --- a/src/components/judging/StatsPanel.tsx +++ b/src/components/judging/StatsPanel.tsx @@ -1,11 +1,6 @@ import Image from "next/image"; -const STATS_PANEL_TILE_STYLES = - "flex h-full flex-col items-center justify-center rounded-lg bg-white px-6 py-8 drop-shadow-md"; -const STATS_PANEL_ICON_CONTAINER_STYLES = - "flex size-12 items-center justify-center rounded-full bg-pastel-pink"; -const STATS_PANEL_NUMBER_STYLES = "my-2 text-5xl font-semibold"; -const STATS_PANEL_SUBHEADER_STYLES = "max-w-[150px] text-center"; +import Card from "../Dashboard/Card"; interface StatsPanelProps { icon: string; @@ -18,15 +13,19 @@ const StatsPanel = (props: StatsPanelProps) => { const { icon, stat, alt, subheader } = props; return ( -
-
+ +
{alt}
-

+

{stat}

-

{subheader}

-
+

{subheader}

+ ); };