163 lines
3.9 KiB
TypeScript

import {
Box,
Button,
Container,
Flex,
Select,
useBreakpointValue,
useToast,
VStack,
} from "@chakra-ui/react";
import { useState } from "react";
import AppealCard from "../../components/AppealCard.js";
import GameAppealCard from "../../components/GameAppealCard.js";
import ReportCard from "../../components/ReportCard.js";
import { useLoaderData } from "@remix-run/react";
export async function loader({ context }: { context: RequestContext }) {
const { current_user: currentUser } = context.data;
if (!currentUser)
throw new Response(null, {
status: 401,
});
const newItemPermissions = {
game_ban: [1 << 5],
inactivity: [1 << 2, 1 << 9, 1 << 10],
infraction: [1 << 0, 1 << 2, 1 << 6, 1 << 7],
};
const newItemNames: { [k: string]: string } = {
game_ban: "Game Ban",
inactivity: "Inactivity Notice",
infraction: "Infraction",
};
const typePermissions = {
appeal: [1 << 0, 1 << 1],
gma: [1 << 5],
report: [1 << 5],
};
const typeNames: { [k: string]: string } = {
appeal: "Discord Appeals",
gma: "Game Appeals",
report: "Game Reports",
};
const allowedNewItems = [];
const allowedTypes = [];
for (const [item, ints] of Object.entries(newItemPermissions)) {
if (ints.find((i) => currentUser.permissions & i))
allowedNewItems.push({ name: newItemNames[item], value: item });
}
for (const [type, ints] of Object.entries(typePermissions)) {
if (ints.find((i) => currentUser.permissions & i))
allowedTypes.push({ name: typeNames[type], value: type });
}
if (!allowedTypes.length)
throw new Response(null, {
status: 403,
});
return {
entry_types: allowedTypes,
item_types: allowedNewItems,
};
}
export function meta() {
return {
title: "Moderation Queue - Car Crushers",
};
}
export default function () {
const pageProps = useLoaderData<typeof loader>();
const isDesktop = useBreakpointValue({ base: false, lg: true });
const entryTypes = [];
const [entries, setEntries] = useState([] as JSX.Element[]);
for (const type of pageProps.entry_types)
entryTypes.push(
<option key={type.value} value={type.value}>
{type.name}
</option>
);
async function updateQueue(
queue_type: string,
show_closed: boolean = false
): Promise<void> {
const queueReq = await fetch(
`/api/mod-queue/list?type=${queue_type}&showClosed=${show_closed}`
);
if (!queueReq.ok) {
const errorData: { error: string } = await queueReq.json();
useToast()({
description: errorData.error,
duration: 10000,
isClosable: true,
status: "error",
title: "Failed to load queue",
});
return;
}
const entryData: { [k: string]: any }[] = await queueReq.json();
const newEntries = [];
for (const entry of entryData) {
switch (queue_type) {
case "appeal":
newEntries.push(<AppealCard {...(entry as AppealCardProps)} />);
break;
case "gma":
newEntries.push(<GameAppealCard {...(entry as GameAppealProps)} />);
break;
case "report":
newEntries.push(<ReportCard {...(entry as ReportCardProps)} />);
break;
}
}
setEntries(newEntries);
}
return (
<Container maxW="container.lg">
<Flex>
<VStack w={isDesktop ? "container.md" : "container.lg"}>
{entries}
</VStack>
<Box display={isDesktop ? undefined : "none"} ml="16px" w="248px">
<Select>{entryTypes}</Select>
</Box>
</Flex>
<Button borderRadius="50%" h="16" w="16">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
fill="currentColor"
viewBox="0 0 16 16"
>
<path d="M8 4a.5.5 0 0 1 .5.5v3h3a.5.5 0 0 1 0 1h-3v3a.5.5 0 0 1-1 0v-3h-3a.5.5 0 0 1 0-1h3v-3A.5.5 0 0 1 8 4z" />
</svg>
</Button>
</Container>
);
}