import { Box, Button, Card, CardBody, CardFooter, Container, Heading, HStack, Link, NumberDecrementStepper, NumberIncrementStepper, NumberInput, NumberInputField, NumberInputStepper, Select, Stack, StackDivider, Text, useToast, VStack, } from "@chakra-ui/react"; import { type LinksFunction } from "@remix-run/cloudflare"; import { type ReactNode, useEffect, useState } from "react"; import stylesheet from "../styles/events-team.css"; import { useLoaderData } from "@remix-run/react"; export const links: LinksFunction = () => { return [{ href: stylesheet, rel: "stylesheet" }]; }; export async function loader({ context }: { context: RequestContext }) { if (!context.data.current_user) throw new Response(null, { status: 401, }); if ( ![1 << 3, 1 << 4, 1 << 12].find( (p) => context.data.current_user.permissions & p, ) ) throw new Response(null, { status: 403, }); return ( await context.env.D1.prepare("SELECT id, name FROM et_members;").all() ).results; } export default function () { const memberData = useLoaderData<typeof loader>(); const [month, setMonth] = useState(new Date().getUTCMonth() + 1); const [year, setYear] = useState(new Date().getUTCFullYear()); const [eventCards, setEventCards] = useState([] as ReactNode[]); const toast = useToast(); async function getEvents() { const eventsResp = await fetch( `/api/events-team/events/list?month=${month}&year=${year}`, ).catch(() => {}); if (!eventsResp?.ok) { let errorMsg = "Unknown error"; try { errorMsg = ((await eventsResp?.json()) as { error: string }).error; } catch {} toast({ description: errorMsg, status: "error", title: "Failed to load events", }); return; } const eventsData: { [k: string]: any }[] = await eventsResp.json(); const newEventCards = []; for (const event of eventsData) { let memberName = event.created_by; const memberDataIdx = memberData.findIndex( (m) => m.id === event.created_by, ); if (memberDataIdx !== -1) memberName = `${memberData[memberDataIdx].name} (${event.created_by})`; newEventCards.push( <Card w="100%"> <CardBody> <Stack divider={<StackDivider />} spacing="4"> <Box> <Heading size="sm">Date</Heading> <Text fontSize="sm" pt="2"> {event.year}-{event.month}-{event.day} </Text> </Box> <Box> <Heading size="sm">Event Type</Heading> <Text fontSize="sm" pt="2"> {event.type.toUpperCase()} </Text> </Box> <Box> <Heading size="sm">Event Details</Heading> <Text fontSize="sm" pt="2"> {event.details} </Text> </Box> {event.type === "rotw" ? ( <Box> <Heading size="sm">Riddle Answer</Heading> <Text fontSize="sm" pt="2"> {event.answer} </Text> </Box> ) : null} <Box> <Heading size="sm">Host</Heading> <Text fontSize="sm" pt="2"> {memberName} </Text> </Box> </Stack> </CardBody> <CardFooter> <Text alignSelf="center" fontSize="sm"> Status:{" "} {event.pending ? "Not completed" : event.approved ? event.performed_at ? "Completed" : "Approved" : "Denied"} </Text> </CardFooter> </Card>, ); } setEventCards(newEventCards); } useEffect(() => { (async () => { await getEvents(); })(); }, []); return ( <Container maxW="container.lg"> <HStack gap="8px" pb="16px"> <Select onChange={(e) => setMonth(parseInt(e.target.value))} value={month} > <option value={1}>January</option> <option value={2}>February</option> <option value={3}>March</option> <option value={4}>April</option> <option value={5}>May</option> <option value={6}>June</option> <option value={7}>July</option> <option value={8}>August</option> <option value={9}>September</option> <option value={10}>October</option> <option value={11}>November</option> <option value={12}>December</option> </Select> <NumberInput defaultValue={year} max={new Date().getUTCFullYear()} precision={0} > <NumberInputField /> <NumberInputStepper> <NumberIncrementStepper /> <NumberDecrementStepper /> </NumberInputStepper> </NumberInput> <Button colorScheme="blue" onClick={async () => await getEvents()}> Go </Button> </HStack> <VStack spacing="8">{eventCards}</VStack> <Link color="#646cff" href="/events-team" mt="16px"> Back to Current Events </Link> </Container> ); }