From 443bf981eb1ea477330370adaa4cf5c94c6182fc Mon Sep 17 00:00:00 2001 From: Sam Der Date: Fri, 26 Jan 2024 11:00:27 -0800 Subject: [PATCH 1/4] Add confirm option for non-hackers in admin portal --- .../app/admin/participants/Participants.tsx | 3 ++- .../components/ParticipantAction.tsx | 27 +++++++++++++++++-- .../components/ParticipantsTable.tsx | 5 +++- apps/site/src/lib/admin/authorization.ts | 11 ++++++++ apps/site/src/lib/admin/useParticipants.ts | 6 +++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/apps/site/src/app/admin/participants/Participants.tsx b/apps/site/src/app/admin/participants/Participants.tsx index 9f7617f9..52d59963 100644 --- a/apps/site/src/app/admin/participants/Participants.tsx +++ b/apps/site/src/app/admin/participants/Participants.tsx @@ -14,6 +14,7 @@ function Participants() { loading, checkInParticipant, releaseParticipantFromWaitlist, + confirmNonHacker, } = useParticipants(); const [checkinParticipant, setCheckinParticipant] = useState(null); @@ -49,6 +50,7 @@ function Participants() { loading={loading} initiateCheckIn={initiateCheckIn} initiatePromotion={initiatePromotion} + initiateConfirm={confirmNonHacker} /> setCheckinParticipant(null)} @@ -60,7 +62,6 @@ function Participants() { onConfirm={sendWaitlistPromote} participant={promoteParticipant} /> - {/* TODO: walk-in promotion modal */} ); } diff --git a/apps/site/src/app/admin/participants/components/ParticipantAction.tsx b/apps/site/src/app/admin/participants/components/ParticipantAction.tsx index ce2afedd..eb313fba 100644 --- a/apps/site/src/app/admin/participants/components/ParticipantAction.tsx +++ b/apps/site/src/app/admin/participants/components/ParticipantAction.tsx @@ -3,7 +3,7 @@ import { useContext } from "react"; import Button from "@cloudscape-design/components/button"; import UserContext from "@/lib/admin/UserContext"; -import { isCheckinLead } from "@/lib/admin/authorization"; +import { isCheckinLead, isNonHacker } from "@/lib/admin/authorization"; import { Status } from "@/lib/admin/useApplicant"; import { Participant } from "@/lib/admin/useParticipants"; import ParticipantActionPopover from "./ParticipantActionPopover"; @@ -12,18 +12,21 @@ interface ParticipantActionProps { participant: Participant; initiateCheckIn: (participant: Participant) => void; initiatePromotion: (participant: Participant) => void; + initiateConfirm: (participant: Participant) => void; } function ParticipantAction({ participant, initiateCheckIn, initiatePromotion, + initiateConfirm, }: ParticipantActionProps) { const { role } = useContext(UserContext); const isCheckin = isCheckinLead(role); const isWaiverSigned = participant.status === Status.signed; const isAccepted = participant.status === Status.accepted; + const nonHacker = isNonHacker(participant.role); const promoteButton = ( + ); + + if (nonHacker) { + if (role !== "director") { + return ( + + {confirmButton} + + ); + } + return confirmButton; + } else if (participant.status === Status.waitlisted) { if (!isCheckin) { return ( diff --git a/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx b/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx index 4e7e55a1..76deb03c 100644 --- a/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx +++ b/apps/site/src/app/admin/participants/components/ParticipantsTable.tsx @@ -17,6 +17,7 @@ interface ParticipantsTableProps { loading: boolean; initiateCheckIn: (participant: Participant) => void; initiatePromotion: (participant: Participant) => void; + initiateConfirm: (participant: Participant) => void; } function ParticipantsTable({ @@ -24,6 +25,7 @@ function ParticipantsTable({ loading, initiateCheckIn, initiatePromotion, + initiateConfirm, }: ParticipantsTableProps) { // TODO: sorting // TODO: search functionality @@ -35,9 +37,10 @@ function ParticipantsTable({ participant={participant} initiateCheckIn={initiateCheckIn} initiatePromotion={initiatePromotion} + initiateConfirm={initiateConfirm} /> ), - [initiateCheckIn, initiatePromotion], + [initiateCheckIn, initiatePromotion, initiateConfirm], ); const emptyMessage = ( diff --git a/apps/site/src/lib/admin/authorization.ts b/apps/site/src/lib/admin/authorization.ts index aff6bf25..83bf65ed 100644 --- a/apps/site/src/lib/admin/authorization.ts +++ b/apps/site/src/lib/admin/authorization.ts @@ -1,6 +1,13 @@ const ADMIN_ROLES = ["director", "reviewer", "checkin_lead"]; const CHECKIN_ROLES = ["director", "checkin_lead"]; const ORGANIZER_ROLES = ["organizer"]; +const NONHACKER_ROLES = [ + "judge", + "sponsor", + "mentor", + "volunteer", + "workshop_lead", +]; export function isApplicationManager(role: string | null) { return role !== null && ADMIN_ROLES.includes(role); @@ -16,3 +23,7 @@ export function isAdminRole(role: string | null) { export function isCheckinLead(role: string | null) { return role !== null && CHECKIN_ROLES.includes(role); } + +export function isNonHacker(role: string | null) { + return role !== null && NONHACKER_ROLES.includes(role); +} diff --git a/apps/site/src/lib/admin/useParticipants.ts b/apps/site/src/lib/admin/useParticipants.ts index 7c0e2537..afbd0f55 100644 --- a/apps/site/src/lib/admin/useParticipants.ts +++ b/apps/site/src/lib/admin/useParticipants.ts @@ -46,12 +46,18 @@ function useParticipants() { await axios.post(`/api/admin/waitlist-release/${participant._id}`); }; + const confirmNonHacker = async (participant: Participant) => { + console.log("Confirmed attendance for non-hacker", participant); + await axios.post(`/api/admin/update-attendance/${participant._id}`); + }; + return { participants: data ?? [], loading: isLoading, error, checkInParticipant, releaseParticipantFromWaitlist, + confirmNonHacker, }; } From 029a30ec16546b2451839a271eeb3d53d2fa6e71 Mon Sep 17 00:00:00 2001 From: Sam Der Date: Fri, 26 Jan 2024 12:57:53 -0800 Subject: [PATCH 2/4] update: use swr mutate on useParticipant hook --- apps/site/src/lib/admin/useParticipants.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/site/src/lib/admin/useParticipants.ts b/apps/site/src/lib/admin/useParticipants.ts index afbd0f55..b87e6bcb 100644 --- a/apps/site/src/lib/admin/useParticipants.ts +++ b/apps/site/src/lib/admin/useParticipants.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import useSWR from "swr"; +import useSWR, { mutate } from "swr"; import { Status, Uid } from "@/lib/admin/useApplicant"; @@ -38,17 +38,20 @@ function useParticipants() { console.log("Checking in", participant); // TODO: implement mutation for showing checked in on each day await axios.post(`/api/admin/checkin/${participant._id}`); + mutate(data); }; const releaseParticipantFromWaitlist = async (participant: Participant) => { console.log(`Promoted to waitlist`, participant); // TODO: implement mutation for showing checked in on each day await axios.post(`/api/admin/waitlist-release/${participant._id}`); + mutate(data); }; const confirmNonHacker = async (participant: Participant) => { console.log("Confirmed attendance for non-hacker", participant); await axios.post(`/api/admin/update-attendance/${participant._id}`); + mutate(data); }; return { From e1880ea34b34830f7b5972de28b9b5a99e537a85 Mon Sep 17 00:00:00 2001 From: Sam Der Date: Fri, 26 Jan 2024 13:19:47 -0800 Subject: [PATCH 3/4] show non-hacker confirm button for waiver signed --- .../src/app/admin/participants/components/ParticipantAction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/site/src/app/admin/participants/components/ParticipantAction.tsx b/apps/site/src/app/admin/participants/components/ParticipantAction.tsx index eb313fba..6afafa85 100644 --- a/apps/site/src/app/admin/participants/components/ParticipantAction.tsx +++ b/apps/site/src/app/admin/participants/components/ParticipantAction.tsx @@ -61,7 +61,7 @@ function ParticipantAction({ ); - if (nonHacker) { + if (nonHacker && isWaiverSigned) { if (role !== "director") { return ( From 9431dada8a141f3ea2a4daf2b19eeb41c2a9e942 Mon Sep 17 00:00:00 2001 From: Sam Der Date: Fri, 26 Jan 2024 13:22:05 -0800 Subject: [PATCH 4/4] refactor: use mutate from useSWR hook --- apps/site/src/lib/admin/authorization.ts | 1 + apps/site/src/lib/admin/useParticipants.ts | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/apps/site/src/lib/admin/authorization.ts b/apps/site/src/lib/admin/authorization.ts index 83bf65ed..42cbd134 100644 --- a/apps/site/src/lib/admin/authorization.ts +++ b/apps/site/src/lib/admin/authorization.ts @@ -24,6 +24,7 @@ export function isCheckinLead(role: string | null) { return role !== null && CHECKIN_ROLES.includes(role); } +// refactor: this function should be placed elsewhere later export function isNonHacker(role: string | null) { return role !== null && NONHACKER_ROLES.includes(role); } diff --git a/apps/site/src/lib/admin/useParticipants.ts b/apps/site/src/lib/admin/useParticipants.ts index b87e6bcb..82c8bf59 100644 --- a/apps/site/src/lib/admin/useParticipants.ts +++ b/apps/site/src/lib/admin/useParticipants.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import useSWR, { mutate } from "swr"; +import useSWR from "swr"; import { Status, Uid } from "@/lib/admin/useApplicant"; @@ -29,7 +29,7 @@ const fetcher = async (url: string) => { }; function useParticipants() { - const { data, error, isLoading } = useSWR( + const { data, error, isLoading, mutate } = useSWR( "/api/admin/participants", fetcher, ); @@ -38,20 +38,20 @@ function useParticipants() { console.log("Checking in", participant); // TODO: implement mutation for showing checked in on each day await axios.post(`/api/admin/checkin/${participant._id}`); - mutate(data); + mutate(); }; const releaseParticipantFromWaitlist = async (participant: Participant) => { console.log(`Promoted to waitlist`, participant); // TODO: implement mutation for showing checked in on each day await axios.post(`/api/admin/waitlist-release/${participant._id}`); - mutate(data); + mutate(); }; const confirmNonHacker = async (participant: Participant) => { console.log("Confirmed attendance for non-hacker", participant); await axios.post(`/api/admin/update-attendance/${participant._id}`); - mutate(data); + mutate(); }; return {