177 lines
4.3 KiB
TypeScript
177 lines
4.3 KiB
TypeScript
import {
|
|
Button,
|
|
Container,
|
|
FormControl,
|
|
FormLabel,
|
|
Input,
|
|
Modal,
|
|
ModalBody,
|
|
ModalCloseButton,
|
|
ModalContent,
|
|
ModalFooter,
|
|
ModalHeader,
|
|
ModalOverlay,
|
|
Table,
|
|
TableCaption,
|
|
TableContainer,
|
|
Tbody,
|
|
Td,
|
|
Th,
|
|
Thead,
|
|
Tr,
|
|
useDisclosure,
|
|
useToast,
|
|
} from "@chakra-ui/react";
|
|
import { useLoaderData } from "@remix-run/react";
|
|
import { useState } from "react";
|
|
|
|
export async function loader({ context }: { context: RequestContext }) {
|
|
if (!context.data.current_user)
|
|
throw new Response(null, {
|
|
status: 401,
|
|
});
|
|
|
|
if (
|
|
![
|
|
"165594923586945025",
|
|
"289372404541554689",
|
|
"396347223736057866",
|
|
].includes(context.data.current_user.id)
|
|
)
|
|
throw new Response(null, {
|
|
status: 403,
|
|
});
|
|
|
|
return (await context.env.DATA.list({ prefix: "gamemod_" }))?.keys ?? [];
|
|
}
|
|
|
|
export default function () {
|
|
const data: { [k: string]: any }[] = useLoaderData<typeof loader>();
|
|
const { isOpen, onClose, onOpen } = useDisclosure();
|
|
const [idToAdd, setIdToAdd] = useState<string>("");
|
|
const [nameToAdd, setNameToAdd] = useState<string>("");
|
|
const toast = useToast();
|
|
|
|
async function addMod(id: string, name: string) {
|
|
const response = await fetch("/api/gme/add", {
|
|
body: JSON.stringify({ name, user: id }),
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
let msg = "Unknown error";
|
|
|
|
try {
|
|
msg = ((await response.json()) as { error: string }).error;
|
|
} catch {}
|
|
|
|
toast({
|
|
description: msg,
|
|
status: "error",
|
|
title: "Cannot add game mod",
|
|
});
|
|
} else {
|
|
toast({
|
|
description: `${name} was added as a game mod`,
|
|
status: "success",
|
|
title: "Game mod added",
|
|
});
|
|
onClose();
|
|
location.reload();
|
|
}
|
|
|
|
setIdToAdd("");
|
|
setNameToAdd("");
|
|
}
|
|
|
|
return (
|
|
<Container maxW="container.lg">
|
|
<TableContainer>
|
|
<Table variant="simple">
|
|
<TableCaption>Currently active game mods</TableCaption>
|
|
<Thead>
|
|
<Tr>
|
|
<Th>ID</Th>
|
|
<Th>Name</Th>
|
|
<Th>Added At</Th>
|
|
<Th>Added By</Th>
|
|
<Th>Remove</Th>
|
|
</Tr>
|
|
</Thead>
|
|
<Tbody>
|
|
{data.map((item) => {
|
|
return (
|
|
<Tr key={item.metadata.id}>
|
|
<Td>{item.metadata.id}</Td>
|
|
<Td>{item.metadata.name}</Td>
|
|
<Td>{item.metadata.created_at}</Td>
|
|
<Td>{item.metadata.created_by}</Td>
|
|
<Td>
|
|
<Button>Remove</Button>
|
|
</Td>
|
|
</Tr>
|
|
);
|
|
})}
|
|
</Tbody>
|
|
</Table>
|
|
</TableContainer>
|
|
<Button alignSelf="end" mt="16px" onClick={onOpen}>
|
|
Add
|
|
</Button>
|
|
<Modal isOpen={isOpen} onClose={onClose}>
|
|
<ModalOverlay />
|
|
<ModalContent>
|
|
<ModalHeader>Add Game Mod</ModalHeader>
|
|
<ModalCloseButton />
|
|
<ModalBody>
|
|
<FormControl>
|
|
<FormLabel>Name</FormLabel>
|
|
<Input
|
|
maxLength={32}
|
|
onChange={(e) => setNameToAdd(e.target.value)}
|
|
value={nameToAdd}
|
|
/>
|
|
</FormControl>
|
|
<br />
|
|
<FormControl pt="16px">
|
|
<FormLabel>ID</FormLabel>
|
|
<Input
|
|
maxLength={19}
|
|
onChange={(e) => setIdToAdd(e.target.value)}
|
|
value={idToAdd}
|
|
/>
|
|
</FormControl>
|
|
</ModalBody>
|
|
<ModalFooter gap="8px">
|
|
<Button
|
|
onClick={() => {
|
|
onClose();
|
|
setIdToAdd("");
|
|
setNameToAdd("");
|
|
}}
|
|
>
|
|
Cancel
|
|
</Button>
|
|
<Button
|
|
colorScheme="blue"
|
|
disabled={
|
|
!idToAdd.match(/\d{17,19}/) ||
|
|
nameToAdd.length < 1 ||
|
|
nameToAdd.length > 32
|
|
}
|
|
onClick={async () => {
|
|
await addMod(idToAdd, nameToAdd);
|
|
}}
|
|
>
|
|
Add
|
|
</Button>
|
|
</ModalFooter>
|
|
</ModalContent>
|
|
</Modal>
|
|
</Container>
|
|
);
|
|
}
|