Add actual functionality
This commit is contained in:
parent
63802c409a
commit
81b411ffa9
@ -1,7 +1,17 @@
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
Box,
|
||||
Button,
|
||||
Heading,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
StackDivider,
|
||||
Table,
|
||||
TableCaption,
|
||||
TableContainer,
|
||||
@ -10,8 +20,12 @@ import {
|
||||
Th,
|
||||
Thead,
|
||||
Tr,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
VStack,
|
||||
} from "@chakra-ui/react";
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { useState } from "react";
|
||||
|
||||
export async function loader({ context }: { context: RequestContext }) {
|
||||
const now = new Date();
|
||||
@ -37,6 +51,24 @@ export async function loader({ context }: { context: RequestContext }) {
|
||||
|
||||
export default function () {
|
||||
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 }) {
|
||||
if (!event.performed_at) return "Approved";
|
||||
@ -47,12 +79,182 @@ export default function () {
|
||||
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 (
|
||||
<>
|
||||
<Alert display={past_cutoff ? undefined : "none"} status="warning">
|
||||
<AlertIcon />
|
||||
The cutoff period for retroactively actioning events has passed.
|
||||
</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>
|
||||
<Table variant="simple">
|
||||
<TableCaption>
|
||||
@ -73,7 +275,15 @@ export default function () {
|
||||
<Td>{event.details}</Td>
|
||||
<Td>{getStatus(event)}</Td>
|
||||
<Td>
|
||||
<Button>Action Menu</Button>
|
||||
<Button
|
||||
disabled={past_cutoff}
|
||||
onClick={() => {
|
||||
setEventData(event);
|
||||
onOpen();
|
||||
}}
|
||||
>
|
||||
Action Menu
|
||||
</Button>
|
||||
</Td>
|
||||
</Tr>
|
||||
))}
|
||||
|
Loading…
x
Reference in New Issue
Block a user