171 lines
5.1 KiB
TypeScript
171 lines
5.1 KiB
TypeScript
import {
|
|
Box,
|
|
Button,
|
|
Card,
|
|
CardBody,
|
|
CardFooter,
|
|
CardHeader,
|
|
Heading,
|
|
ListItem,
|
|
Stack,
|
|
StackDivider,
|
|
Text,
|
|
UnorderedList,
|
|
useToast,
|
|
} from "@chakra-ui/react";
|
|
import { useState } from "react";
|
|
|
|
export default function (
|
|
props: InactivityNoticeProps & { port?: MessagePort },
|
|
) {
|
|
const toast = useToast();
|
|
const [loading, setLoading] = useState(false);
|
|
|
|
async function makeDecision(accepted: boolean) {
|
|
setLoading(true);
|
|
const decisionReq = await fetch(`/api/inactivity/${props.id}`, {
|
|
body: JSON.stringify({ accepted }),
|
|
headers: {
|
|
"content-type": "application/json",
|
|
},
|
|
method: "POST",
|
|
});
|
|
|
|
if (!decisionReq.ok) {
|
|
setLoading(false);
|
|
toast({
|
|
description: ((await decisionReq.json()) as { error: string }).error,
|
|
isClosable: true,
|
|
status: "error",
|
|
title: "Oops",
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
toast({
|
|
description: `Inactivity notice ${accepted ? "accepted" : "denied"}.`,
|
|
isClosable: true,
|
|
status: "success",
|
|
title: "Success",
|
|
});
|
|
|
|
setLoading(false);
|
|
}
|
|
|
|
const Approved = () => (
|
|
<svg fill="currentColor" height="16" viewBox="0 0 16 16" width="16">
|
|
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z" />
|
|
</svg>
|
|
);
|
|
|
|
const Denied = () => (
|
|
<svg fill="currentColor" height="16" viewBox="0 0 16 16" width="16">
|
|
<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z" />
|
|
</svg>
|
|
);
|
|
|
|
const Pending = () => (
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="16"
|
|
height="16"
|
|
fill="currentColor"
|
|
viewBox="0 0 16 16"
|
|
>
|
|
<path d="M2.5 15a.5.5 0 1 1 0-1h1v-1a4.5 4.5 0 0 1 2.557-4.06c.29-.139.443-.377.443-.59v-.7c0-.213-.154-.451-.443-.59A4.5 4.5 0 0 1 3.5 3V2h-1a.5.5 0 0 1 0-1h11a.5.5 0 0 1 0 1h-1v1a4.5 4.5 0 0 1-2.557 4.06c-.29.139-.443.377-.443.59v.7c0 .213.154.451.443.59A4.5 4.5 0 0 1 12.5 13v1h1a.5.5 0 0 1 0 1zm2-13v1c0 .537.12 1.045.337 1.5h6.326c.216-.455.337-.963.337-1.5V2zm3 6.35c0 .701-.478 1.236-1.011 1.492A3.5 3.5 0 0 0 4.5 13s.866-1.299 3-1.48zm1 0v3.17c2.134.181 3 1.48 3 1.48a3.5 3.5 0 0 0-1.989-3.158C8.978 9.586 8.5 9.052 8.5 8.351z" />
|
|
</svg>
|
|
);
|
|
|
|
return (
|
|
<Card w="100%">
|
|
<CardHeader>
|
|
<Heading size="md">Inactivity Notice for {props.user.username}</Heading>
|
|
<Text fontSize="xs">ID: {props.user.id}</Text>
|
|
</CardHeader>
|
|
<CardBody>
|
|
<Stack divider={<StackDivider />}>
|
|
<Box>
|
|
<Heading size="xs">Reason for Inactivity</Heading>
|
|
<Text>{props.reason}</Text>
|
|
</Box>
|
|
<Box>
|
|
<Heading size="xs">Start Date</Heading>
|
|
<Text>{new Date(props.start).toLocaleDateString()}</Text>
|
|
</Box>
|
|
<Box>
|
|
<Heading size="xs">End Date</Heading>
|
|
<Text>{new Date(props.end).toLocaleDateString()}</Text>
|
|
</Box>
|
|
{typeof props.hiatus === "boolean" ? (
|
|
<Box>
|
|
<Heading size="xs">Notice Type</Heading>
|
|
<Text>
|
|
{props.hiatus ? "Hiatus/Inactivity" : "Activity Decrease"}
|
|
</Text>
|
|
</Box>
|
|
) : null}
|
|
<Box>
|
|
<Heading size="xs">Decisions</Heading>
|
|
<UnorderedList>
|
|
{props.departments.map((d) => {
|
|
const dept = d as "ET" | "DM" | "FM" | "WM";
|
|
|
|
return (
|
|
<ListItem>
|
|
<Stack alignItems="center" direction="row">
|
|
<Text>{d}: </Text>
|
|
{typeof props.decisions[dept] === "boolean" ? (
|
|
props.decisions[dept] ? (
|
|
<Approved />
|
|
) : (
|
|
<Denied />
|
|
)
|
|
) : (
|
|
<Pending />
|
|
)}
|
|
</Stack>
|
|
</ListItem>
|
|
);
|
|
})}
|
|
</UnorderedList>
|
|
</Box>
|
|
</Stack>
|
|
</CardBody>
|
|
<CardFooter
|
|
display={
|
|
props.departments.length !==
|
|
Object.values(
|
|
props.decisions as {
|
|
[k: string]: boolean;
|
|
},
|
|
).length
|
|
? undefined
|
|
: "none"
|
|
}
|
|
pb="4px"
|
|
>
|
|
<Box>
|
|
<Button
|
|
colorScheme="red"
|
|
onClick={async () => await makeDecision(false)}
|
|
isLoading={loading}
|
|
loadingText="Processing..."
|
|
>
|
|
Deny
|
|
</Button>
|
|
<Button
|
|
colorScheme="blue"
|
|
ml="8px"
|
|
onClick={async () => await makeDecision(true)}
|
|
isLoading={loading}
|
|
loadingText="Processing..."
|
|
>
|
|
Accept
|
|
</Button>
|
|
</Box>
|
|
</CardFooter>
|
|
</Card>
|
|
);
|
|
}
|