diff --git a/app/routes/events-team.tsx b/app/routes/events-team.tsx index 3ec3248..8f16032 100644 --- a/app/routes/events-team.tsx +++ b/app/routes/events-team.tsx @@ -23,7 +23,7 @@ import { Text, useDisclosure, useToast, - VStack, + VStack } from "@chakra-ui/react"; import { useLoaderData } from "@remix-run/react"; import { useState } from "react"; @@ -34,62 +34,62 @@ import { type LinksFunction } from "@remix-run/cloudflare"; export const links: LinksFunction = () => { return [ { href: stylesheet, rel: "stylesheet" }, - { href: calendarStyles, rel: "stylesheet" }, + { href: calendarStyles, rel: "stylesheet" } ]; }; export async function loader({ context }: { context: RequestContext }) { if (!context.data.current_user) throw new Response(null, { - status: 401, + status: 401 }); if ( ![1 << 3, 1 << 4, 1 << 12].find( - (p) => context.data.current_user.permissions & p, + (p) => context.data.current_user.permissions & p ) ) throw new Response(null, { - status: 403, + status: 403 }); const now = new Date(); const monthEventList = await context.env.D1.prepare( - "SELECT answer, approved, created_by, day, details, id, month, pending, performed_at, reached_minimum_player_count, type, year FROM events WHERE month = ? AND year = ? ORDER BY day ASC;", + "SELECT answer, approved, created_by, day, details, id, month, pending, performed_at, reached_minimum_player_count, type, year FROM events WHERE month = ? AND year = ? ORDER BY day ASC;" ) .bind(now.getUTCMonth() + 1, now.getUTCFullYear()) .all(); if (monthEventList.error) throw new Response(null, { - status: 500, + status: 500 }); const membersList = await context.env.D1.prepare( - "SELECT id, name FROM et_members WHERE id IN (SELECT created_by FROM events WHERE month = ? AND year = ?);", + "SELECT id, name FROM et_members WHERE id IN (SELECT created_by FROM events WHERE month = ? AND year = ?);" ) .bind(now.getUTCMonth() + 1, now.getUTCFullYear()) .all(); if (membersList.error) throw new Response(null, { - status: 500, + status: 500 }); return { can_approve: Boolean( - [1 << 4, 1 << 12].find((p) => context.data.current_user.permissions & p), + [1 << 4, 1 << 12].find((p) => context.data.current_user.permissions & p) ), events: monthEventList.results, - members: membersList.results as { id: string; name: string }[], + members: membersList.results as { id: string; name: string }[] }; } -export default function () { +export default function() { const { can_approve, events, - members, + members }: { can_approve: boolean; events: { [k: string]: any }[]; @@ -100,12 +100,17 @@ export default function () { const { isOpen: isCompleteOpen, onClose: closeComplete, - onOpen: openComplete, + onOpen: openComplete } = useDisclosure(); const { isOpen: isAnsweredOpen, onClose: closeAnswered, - onOpen: openAnswered, + onOpen: openAnswered + } = useDisclosure(); + const { + isOpen: isForgottenOpen, + onClose: onForgottenClose, + onOpen: onForgottenOpen } = useDisclosure(); const toast = useToast(); const [selectedEvent, setSelectedEvent] = useState(""); @@ -117,10 +122,10 @@ export default function () { { body: JSON.stringify({ approved }), headers: { - "content-type": "application/json", + "content-type": "application/json" }, - method: "POST", - }, + method: "POST" + } ); if (!decisionResp.ok) { @@ -128,12 +133,13 @@ export default function () { try { errorMsg = ((await decisionResp.json()) as { error: string }).error; - } catch {} + } catch { + } toast({ description: errorMsg, status: "error", - title: "Oops!", + title: "Oops!" }); return; @@ -142,7 +148,7 @@ export default function () { toast({ description: `Event ${approved ? "approved" : "rejected"}`, status: "success", - title: "Success", + title: "Success" }); const newEventData = eventData; @@ -160,10 +166,10 @@ export default function () { { body: "{}", headers: { - "content-type": "application/json", + "content-type": "application/json" }, - method: "POST", - }, + method: "POST" + } ); if (!certifyResp.ok) { @@ -171,12 +177,13 @@ export default function () { try { errorMsg = ((await certifyResp.json()) as { error: string }).error; - } catch {} + } catch { + } toast({ description: errorMsg, status: "error", - title: "Failed to certify game night", + title: "Failed to certify game night" }); return; @@ -185,13 +192,13 @@ export default function () { toast({ description: "Game night certified", status: "success", - title: "Success", + title: "Success" }); const newEventData = eventData; newEventData[ eventData.findIndex((e) => e.id === eventId) - ].reached_minimum_player_count = true; + ].reached_minimum_player_count = true; setEventData([...newEventData]); setSelectedEvent(""); @@ -201,9 +208,9 @@ export default function () { const answerResp = await fetch(`/api/events-team/events/${eventId}/solve`, { body: "{}", headers: { - "content-type": "application/json", + "content-type": "application/json" }, - method: "POST", + method: "POST" }); closeAnswered(); @@ -212,7 +219,7 @@ export default function () { toast({ description: "Failed to mark as solved", status: "error", - title: "Oops", + title: "Oops" }); return; @@ -232,10 +239,10 @@ export default function () { { body: "{}", headers: { - "content-type": "application/json", + "content-type": "application/json" }, - method: "POST", - }, + method: "POST" + } ); closeComplete(); @@ -245,12 +252,13 @@ export default function () { try { msg = ((await completeResp.json()) as { error: string }).error; - } catch {} + } catch { + } toast({ description: msg, status: "error", - title: "Failed to complete", + title: "Failed to complete" }); return; @@ -259,7 +267,7 @@ export default function () { toast({ description: "Event marked as completed", status: "success", - title: "Success", + title: "Success" }); const newEventData = eventData; @@ -272,6 +280,44 @@ export default function () { setSelectedEvent(""); } + async function markForgotten(eventId: string) { + const forgottenResp = await fetch( + `/api/events-team/events/${eventId}/forgotten`, + { + body: "{}", + headers: { + "content-type": "application/json" + }, + method: "POST" + } + ); + + onForgottenClose(); + + if (!forgottenResp.ok) { + let msg = "Unknown error"; + + try { + msg = ((await forgottenResp.json()) as { error: string }).error; + } catch { + } + + toast({ + description: msg, + status: "error", + title: "Failed to forget" + }); + + return; + } + + const newEventData = eventData; + + newEventData[eventData.findIndex((e) => e.id === eventId)].performed_at = 0; + setEventData([...newEventData]); + setSelectedEvent(""); + } + return ( @@ -345,20 +391,33 @@ export default function () { + + + + Mark as Forgotten + + Are you sure you want to mark this event as forgotten? The creator will be given a 5 point + penalty. + + + ) : null} - {can_approve && !event.pending && !event.performed_at ? ( - + {can_approve && + !event.pending && + typeof event.performed_at !== "number" ? ( + <> + + + ) : null} {can_approve && !event.pending &&