Add actual functionality

This commit is contained in:
Regalijan 2024-11-18 15:53:51 -05:00
parent 63802c409a
commit 81b411ffa9
Signed by: regalijan
GPG Key ID: 5D4196DA269EF520

View File

@ -1,7 +1,17 @@
import { import {
Alert, Alert,
AlertIcon, AlertIcon,
Box,
Button, Button,
Heading,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalFooter,
ModalHeader,
ModalOverlay,
StackDivider,
Table, Table,
TableCaption, TableCaption,
TableContainer, TableContainer,
@ -10,8 +20,12 @@ import {
Th, Th,
Thead, Thead,
Tr, Tr,
useDisclosure,
useToast,
VStack,
} from "@chakra-ui/react"; } from "@chakra-ui/react";
import { useLoaderData } from "@remix-run/react"; import { useLoaderData } from "@remix-run/react";
import { useState } from "react";
export async function loader({ context }: { context: RequestContext }) { export async function loader({ context }: { context: RequestContext }) {
const now = new Date(); const now = new Date();
@ -37,6 +51,24 @@ export async function loader({ context }: { context: RequestContext }) {
export default function () { export default function () {
const { events, past_cutoff } = useLoaderData<typeof loader>(); const { events, past_cutoff } = useLoaderData<typeof loader>();
const { isOpen, onClose, onOpen } = useDisclosure();
const [eventData, setEventData] = useState({} as { [k: string]: any });
const [isBrowserSupported, setIsBrowserSupported] = useState(true);
const toast = useToast();
async function displayErrorToast(response: Response, title: string) {
let msg = "Unknown error";
try {
msg = ((await response.json()) as { error: string }).error;
} catch {}
toast({
description: msg,
status: "error",
title,
});
}
function getStatus(event: { [k: string]: string | number }) { function getStatus(event: { [k: string]: string | number }) {
if (!event.performed_at) return "Approved"; if (!event.performed_at) return "Approved";
@ -47,12 +79,182 @@ export default function () {
return "Completed"; return "Completed";
} }
async function certify() {
const response = await fetch(
`/api/events-team/events/${eventData.id}/certify`,
{
body: "{}",
headers: {
"content-type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
await displayErrorToast(response, "Failed to certify game night");
return;
}
toast({
status: "success",
title: "Game night certified",
});
const newData = structuredClone(eventData);
newData.reached_minimum_player_count = 1;
setEventData(newData);
}
async function completed() {
const response = await fetch(
`/api/events-team/events/${eventData.id}/complete`,
{
body: "{}",
headers: {
"content-type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
await displayErrorToast(response, "Failed to mark as completed");
return;
}
toast({
status: "success",
title: "Event marked as complete",
});
const newData = structuredClone(eventData);
newData.performed_at = Date.now();
setEventData(newData);
}
async function forgotten() {
const response = await fetch(
`/api/events-team/events/${eventData.id}/forgotten`,
{
body: "{}",
headers: {
"content-type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
await displayErrorToast(response, "Failed to mark as forgotten");
return;
}
toast({
title: "Event marked as forgotten",
status: "success",
});
const newData = structuredClone(eventData);
newData.performed_at = 0;
setEventData(newData);
}
async function solve() {
const response = await fetch(
`/api/events-team/events/${eventData.id}/solve`,
{
body: "{}",
headers: {
"content-type": "application/json",
},
method: "POST",
},
);
if (!response.ok) {
await displayErrorToast(response, "Failed to mark as solved");
return;
}
toast({
status: "success",
title: "Riddle marked as solved",
});
const newData = structuredClone(eventData);
newData.answered_at = Date.now();
setEventData(newData);
}
return ( return (
<> <>
<Alert display={past_cutoff ? undefined : "none"} status="warning"> <Alert display={past_cutoff ? undefined : "none"} status="warning">
<AlertIcon /> <AlertIcon />
The cutoff period for retroactively actioning events has passed. The cutoff period for retroactively actioning events has passed.
</Alert> </Alert>
<Alert display={isBrowserSupported ? undefined : "none"} status="error">
<AlertIcon />
This browser is unsupported. Please upgrade to a browser not several
years out of date.
</Alert>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Action Menu</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack divider={<StackDivider />}>
<Box gap="8px">
<Heading size="xs">Completion</Heading>
<Button
disabled={typeof eventData.completed_at === "number"}
onClick={async () => await completed()}
>
Mark as Complete
</Button>
<Button
disabled={typeof eventData.completed_at === "number"}
onClick={async () => await forgotten()}
>
Mark as Forgotten
</Button>
</Box>
{eventData.type === "rotw" ? (
<Box gap="8px">
<Heading size="xs">Solved Status</Heading>
<Button
disabled={Boolean(eventData.answered_at)}
onClick={async () => await solve()}
>
{eventData.answered_at ? "Solved" : "Mark as Solved"}
</Button>
</Box>
) : null}
{eventData.type === "gamenight" ? (
<Box gap="8px">
<Heading size="xs">Certified Status</Heading>
<Button
disabled={Boolean(eventData.reached_minimum_player_count)}
onClick={async () => await certify()}
>
{eventData.reached_minimum_player_count
? "Certified"
: "Certify"}
</Button>
</Box>
) : null}
</VStack>
</ModalBody>
<ModalFooter>
<Button onClick={onClose}>Close</Button>
</ModalFooter>
</ModalContent>
</Modal>
<TableContainer> <TableContainer>
<Table variant="simple"> <Table variant="simple">
<TableCaption> <TableCaption>
@ -73,7 +275,15 @@ export default function () {
<Td>{event.details}</Td> <Td>{event.details}</Td>
<Td>{getStatus(event)}</Td> <Td>{getStatus(event)}</Td>
<Td> <Td>
<Button>Action Menu</Button> <Button
disabled={past_cutoff}
onClick={() => {
setEventData(event);
onOpen();
}}
>
Action Menu
</Button>
</Td> </Td>
</Tr> </Tr>
))} ))}