Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Add strike creation capabilities
- Loading branch information
Showing
2 changed files
with
255 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,240 @@ | ||
import { | ||
Button, | ||
Container, | ||
Heading, | ||
Link, | ||
Modal, | ||
ModalBody, | ||
ModalCloseButton, | ||
ModalContent, | ||
ModalFooter, | ||
ModalHeader, | ||
ModalOverlay, | ||
Table, | ||
TableContainer, | ||
Tbody, | ||
Td, | ||
Text, | ||
Textarea, | ||
Th, | ||
Thead, | ||
Tr, | ||
useDisclosure, | ||
useToast, | ||
} from "@chakra-ui/react"; | ||
import { LoaderFunctionArgs } from "@remix-run/cloudflare"; | ||
import { useLoaderData } from "@remix-run/react"; | ||
import { useState } from "react"; | ||
|
||
export async function loader({ | ||
context, | ||
params, | ||
}: { | ||
context: RequestContext; | ||
params: LoaderFunctionArgs & { uid: string }; | ||
}) { | ||
const { current_user: user } = context.data; | ||
|
||
if (!user) | ||
throw new Response(null, { | ||
status: 401, | ||
}); | ||
|
||
if (![1 << 3, 1 << 4, 1 << 12].find((p) => user.permissions & p)) | ||
throw new Response(null, { | ||
status: 403, | ||
}); | ||
|
||
const strikeData = await context.env.D1.prepare( | ||
"SELECT * FROM et_strikes WHERE user = ?;", | ||
) | ||
.bind(params.uid) | ||
.all(); | ||
|
||
return { | ||
can_manage: Boolean([1 << 4, 1 << 12].find((p) => user.permissions & p)), | ||
strikes: strikeData.results, | ||
user: params.uid, | ||
}; | ||
} | ||
|
||
export default function () { | ||
const { can_manage, strikes, user } = useLoaderData<typeof loader>(); | ||
const [strikeData, setStrikeData] = useState(strikes); | ||
const toast = useToast(); | ||
const [rmStrikeId, setRmStrikeId] = useState(""); | ||
const [strikeReason, setStrikeReason] = useState(""); | ||
|
||
async function removeStrike(id: string) { | ||
const removeResp = await fetch(`/api/events-team/strikes/${id}`, { | ||
method: "DELETE", | ||
}); | ||
|
||
if (!removeResp.ok) { | ||
let msg = "Unknown error"; | ||
|
||
try { | ||
msg = ((await removeResp.json()) as { error: string }).error; | ||
} catch {} | ||
|
||
toast({ | ||
description: msg, | ||
status: "error", | ||
title: "Failed to remove strike", | ||
}); | ||
|
||
return; | ||
} | ||
|
||
toast({ | ||
description: `Strike ${id} was removed`, | ||
status: "success", | ||
title: "Strike Removed", | ||
}); | ||
|
||
setStrikeData(strikeData.filter((strike) => strike.id !== id)); | ||
closeRmStrike(); | ||
} | ||
|
||
async function addStrike() { | ||
const addStrikeResp = await fetch("/api/events-team/strikes/new", { | ||
body: JSON.stringify({ | ||
reason: strikeReason, | ||
user, | ||
}), | ||
headers: { | ||
"content-type": "application/json", | ||
}, | ||
method: "POST", | ||
}); | ||
|
||
if (!addStrikeResp.ok) { | ||
let msg = "Unknown error"; | ||
|
||
try { | ||
msg = ((await addStrikeResp.json()) as { error: string }).error; | ||
} catch {} | ||
|
||
toast({ | ||
description: msg, | ||
status: "error", | ||
title: "Failed to add strike", | ||
}); | ||
|
||
return; | ||
} | ||
|
||
toast({ | ||
description: "Strike added", | ||
status: "success", | ||
title: "Success", | ||
}); | ||
|
||
const newStrikeData = strikeData; | ||
|
||
newStrikeData.push(await addStrikeResp.json()); | ||
setStrikeData(newStrikeData); | ||
closeAddStrike(); | ||
} | ||
|
||
const { | ||
isOpen: rmStrikeOpen, | ||
onClose: closeRmStrike, | ||
onOpen: openRmStrike, | ||
} = useDisclosure(); | ||
const { | ||
isOpen: addStrikeOpen, | ||
onClose: closeAddStrike, | ||
onOpen: openAddStrike, | ||
} = useDisclosure(); | ||
|
||
return ( | ||
<Container maxW="container.lg"> | ||
<Modal isOpen={rmStrikeOpen} onClose={closeRmStrike}> | ||
<ModalOverlay /> | ||
<ModalContent> | ||
<ModalHeader>Remove Strike</ModalHeader> | ||
<ModalCloseButton /> | ||
<ModalBody> | ||
<Text>Are you sure you want to remove this strike?</Text> | ||
</ModalBody> | ||
<ModalFooter> | ||
<Button mr="8px">No</Button> | ||
<Button | ||
colorScheme="red" | ||
onClick={async () => await removeStrike(rmStrikeId)} | ||
> | ||
Yes | ||
</Button> | ||
</ModalFooter> | ||
</ModalContent> | ||
</Modal> | ||
<Modal isOpen={addStrikeOpen} onClose={closeAddStrike}> | ||
<ModalOverlay /> | ||
<ModalContent> | ||
<ModalHeader>Add Strike</ModalHeader> | ||
<ModalCloseButton /> | ||
<ModalBody> | ||
<Heading mb="8px" size="xs"> | ||
Reason | ||
</Heading> | ||
<Textarea | ||
onChange={(e) => setStrikeReason(e.target.value)} | ||
placeholder="Strike reason" | ||
value={strikeReason} | ||
/> | ||
</ModalBody> | ||
<ModalFooter> | ||
<Button | ||
mr="8px" | ||
onClick={() => { | ||
closeAddStrike(); | ||
setStrikeReason(""); | ||
}} | ||
> | ||
Cancel | ||
</Button> | ||
<Button colorScheme="red" onClick={async () => await addStrike()}> | ||
Add Strike | ||
</Button> | ||
</ModalFooter> | ||
</ModalContent> | ||
</Modal> | ||
<Heading my="16px">Strikes</Heading> | ||
<TableContainer> | ||
<Table variant="simple"> | ||
<Thead> | ||
<Th>Time Added</Th> | ||
<Th>Added By</Th> | ||
<Th>Reason</Th> | ||
<Th>Remove</Th> | ||
</Thead> | ||
<Tbody> | ||
{strikeData.map((strike: { [k: string]: any }) => ( | ||
<Tr> | ||
<Td>{new Date(strike.created_at).toUTCString()}</Td> | ||
<Td>{strike.created_by}</Td> | ||
<Td>{strike.reason}</Td> | ||
<Td> | ||
{can_manage ? ( | ||
<Link | ||
onClick={() => { | ||
setRmStrikeId(strike.id); | ||
openRmStrike(); | ||
}} | ||
> | ||
Remove | ||
</Link> | ||
) : null} | ||
</Td> | ||
</Tr> | ||
))} | ||
</Tbody> | ||
</Table> | ||
</TableContainer> | ||
<Link color="#646cff" onClick={openAddStrike} py="16px"> | ||
Add Strike | ||
</Link> | ||
</Container> | ||
); | ||
} |