Remix migration
This commit is contained in:
231
app/routes/appeals.tsx
Normal file
231
app/routes/appeals.tsx
Normal file
@ -0,0 +1,231 @@
|
||||
import {
|
||||
Alert,
|
||||
AlertDescription,
|
||||
AlertIcon,
|
||||
AlertTitle,
|
||||
Box,
|
||||
Button,
|
||||
Container,
|
||||
Flex,
|
||||
Heading,
|
||||
Modal,
|
||||
ModalBody,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalFooter,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Spacer,
|
||||
Text,
|
||||
Textarea,
|
||||
useDisclosure,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useLoaderData } from "@remix-run/react";
|
||||
import { useState } from "react";
|
||||
import Success from "../../components/Success.js";
|
||||
|
||||
export async function loader({ context }: { context: RequestContext }) {
|
||||
if (!context.data.current_user)
|
||||
throw new Response(null, {
|
||||
status: 401,
|
||||
});
|
||||
|
||||
const { current_user: currentUser } = context.data;
|
||||
const dataKV = context.env.DATA;
|
||||
const disabled = await dataKV.get("appeal_disabled");
|
||||
|
||||
return {
|
||||
can_appeal:
|
||||
!Boolean(disabled) &&
|
||||
!Boolean(await dataKV.get(`blockedappeal_${currentUser.id}`)) &&
|
||||
!Boolean(
|
||||
(
|
||||
await dataKV.list({
|
||||
prefix: `appeal_${currentUser.id}`,
|
||||
})
|
||||
).keys.find((appeal) => (appeal.metadata as { [k: string]: any }).open)
|
||||
),
|
||||
can_toggle:
|
||||
currentUser.permissions & (1 << 0) || currentUser.permissions & (1 << 11),
|
||||
disabled: Boolean(disabled),
|
||||
};
|
||||
}
|
||||
|
||||
export default function () {
|
||||
const pageProps = useLoaderData<typeof loader>();
|
||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||
const [showSuccess, setShowSuccess] = useState(false);
|
||||
const toast = useToast();
|
||||
|
||||
async function submit() {
|
||||
const learned = (document.getElementById("learned") as HTMLInputElement)
|
||||
.value;
|
||||
const whyBanned = (document.getElementById("whyBanned") as HTMLInputElement)
|
||||
.value;
|
||||
const whyUnban = (document.getElementById("whyUnban") as HTMLInputElement)
|
||||
.value;
|
||||
|
||||
const submitReq = await fetch("/api/appeals/submit", {
|
||||
body: JSON.stringify({
|
||||
learned,
|
||||
whyBanned,
|
||||
whyUnban,
|
||||
}),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
}).catch(() => {});
|
||||
|
||||
if (!submitReq)
|
||||
return toast({
|
||||
description: "Please check your internet and try again",
|
||||
duration: 10000,
|
||||
isClosable: true,
|
||||
status: "error",
|
||||
title: "Request Failed",
|
||||
});
|
||||
|
||||
if (!submitReq.ok)
|
||||
return toast({
|
||||
description: ((await submitReq.json()) as { error: string }).error,
|
||||
duration: 10000,
|
||||
isClosable: true,
|
||||
status: "error",
|
||||
title: "Error",
|
||||
});
|
||||
|
||||
setShowSuccess(true);
|
||||
}
|
||||
|
||||
async function toggle(active: boolean) {
|
||||
const toggleReq = await fetch("/api/appeals/toggle", {
|
||||
body: JSON.stringify({ active }),
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
},
|
||||
method: "POST",
|
||||
});
|
||||
|
||||
if (!toggleReq.ok)
|
||||
return toast({
|
||||
description: ((await toggleReq.json()) as { error: string }).error,
|
||||
duration: 10000,
|
||||
isClosable: true,
|
||||
status: "error",
|
||||
title: "Error",
|
||||
});
|
||||
|
||||
toast({
|
||||
description: `The appeals form is now ${active ? "opened" : "closed"}.`,
|
||||
isClosable: true,
|
||||
status: "success",
|
||||
title: `Appeals ${active ? "enabled" : "disabled"}`,
|
||||
});
|
||||
|
||||
onClose();
|
||||
await new Promise((p) => setTimeout(p, 5000));
|
||||
}
|
||||
|
||||
return showSuccess ? (
|
||||
<Success
|
||||
heading="Appeal Submitted"
|
||||
message="You will receive an email when we reach a decision."
|
||||
/>
|
||||
) : (
|
||||
<Container maxW="container.md" pt="4vh" textAlign="start">
|
||||
<Alert
|
||||
borderRadius="8px"
|
||||
display={pageProps.disabled ? "flex" : "none"}
|
||||
mb="16px"
|
||||
status="error"
|
||||
>
|
||||
<AlertIcon />
|
||||
<Box>
|
||||
<AlertTitle>Appeals Closed</AlertTitle>
|
||||
<AlertDescription>
|
||||
We are currently not accepting appeals.
|
||||
</AlertDescription>
|
||||
</Box>
|
||||
</Alert>
|
||||
<Flex>
|
||||
<Spacer />
|
||||
<Button display={pageProps.can_toggle ? "" : "none"} onClick={onOpen}>
|
||||
{pageProps.disabled ? "Enable" : "Disable"} Appeals
|
||||
</Button>
|
||||
</Flex>
|
||||
<br />
|
||||
<Modal isCentered isOpen={isOpen} onClose={onClose}>
|
||||
<ModalOverlay />
|
||||
<ModalContent>
|
||||
<ModalHeader>Toggle appeals?</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<ModalBody>
|
||||
<Text>
|
||||
Are you sure you want to{" "}
|
||||
{pageProps.disabled ? "enable" : "disable"} appeals?
|
||||
</Text>
|
||||
</ModalBody>
|
||||
<ModalFooter style={{ gap: "8px" }}>
|
||||
<Button onClick={onClose} variant="ghost">
|
||||
No
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async () => await toggle(pageProps.disabled)}
|
||||
variant="danger"
|
||||
>
|
||||
Yes
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
<Heading size="xl">Discord Appeals</Heading>
|
||||
<br />
|
||||
<Text fontSize="md">
|
||||
This is for Discord bans only! See the support page if you were banned
|
||||
from the game.
|
||||
</Text>
|
||||
<br />
|
||||
<br />
|
||||
<Heading size="md">Why were you banned?</Heading>
|
||||
<br />
|
||||
<Textarea
|
||||
disabled={!pageProps.can_appeal}
|
||||
id="whyBanned"
|
||||
maxLength={500}
|
||||
placeholder="Your response"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Heading size="md">Why should we unban you?</Heading>
|
||||
<br />
|
||||
<Textarea
|
||||
disabled={!pageProps.can_appeal}
|
||||
id="whyUnban"
|
||||
maxLength={2000}
|
||||
placeholder="Your response"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<Heading size="md">What have you learned from your mistake?</Heading>
|
||||
<br />
|
||||
<Textarea
|
||||
disabled={!pageProps.can_appeal}
|
||||
id="learned"
|
||||
maxLength={2000}
|
||||
placeholder="Your response"
|
||||
/>
|
||||
<br />
|
||||
<br />
|
||||
<Button
|
||||
disabled={pageProps.can_appeal}
|
||||
onClick={async () => await submit()}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</Container>
|
||||
);
|
||||
}
|
Reference in New Issue
Block a user