diff --git a/flask/api.py b/flask/api.py index 0c8b6e4..b57efed 100644 --- a/flask/api.py +++ b/flask/api.py @@ -89,7 +89,7 @@ def sub_order_set_create(username, sub): return jsonify(new_order_pool.to_dict()) -@api.route('/subs//sets/', methods = ['GET', 'POST']) +@api.route('/subs//sets/', methods = ['GET', 'POST', 'DELETE']) @authorized_sub def sub_order_set(username, set_id, sub): op = orders_pool(sub.id, set_id) @@ -160,5 +160,8 @@ def sub_order_set(username, set_id, sub): except: transaction.rollback() abort(500) + elif request.method == 'DELETE': + op.delete_instance(recursive=True) + return ('', 204) return jsonify(op.to_dict()) diff --git a/flask/vite/src/ConfirmDialogButton.tsx b/flask/vite/src/ConfirmDialogButton.tsx new file mode 100644 index 0000000..55faa2f --- /dev/null +++ b/flask/vite/src/ConfirmDialogButton.tsx @@ -0,0 +1,36 @@ +import React from "react"; +import { useDisclosure } from "@mantine/hooks"; + +import { Button, Modal, Text, Flex } from "@mantine/core"; + +export const ConfirmDialogButton: React.FC<{ + text: string; + buttonText: string; + buttonColor: string; + onConfirm: () => void; + children: React.ReactNode; +}> = ({ text, buttonText, buttonColor, onConfirm, children }) => { + const [opened, { open, close }] = useDisclosure(); + + const handleConfirm = React.useCallback(() => { + close(); + onConfirm(); + }, [close, onConfirm]); + + return ( + <> + + {text} + + + + + + + + ); +}; diff --git a/flask/vite/src/NavigateButton.tsx b/flask/vite/src/NavigateButton.tsx new file mode 100644 index 0000000..63606f0 --- /dev/null +++ b/flask/vite/src/NavigateButton.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import { Button } from "@mantine/core"; +import { useNavigate } from "react-router"; + +export const NavigateButton: React.FC<{ + children: React.ReactNode; + to: string; +}> = ({ children, to }) => { + const navigate = useNavigate(); + + const handleClick = React.useCallback(() => { + navigate(to); + }, [to]); + + return ( + + ); +}; diff --git a/flask/vite/src/SubOrderSet.tsx b/flask/vite/src/SubOrderSet.tsx index ff46624..ab25860 100644 --- a/flask/vite/src/SubOrderSet.tsx +++ b/flask/vite/src/SubOrderSet.tsx @@ -39,6 +39,22 @@ export const subOrderSetLoader = async ({ response.json(), ); +export const subOrderSetAction = async ({ + request, + params: { username, set_id: id }, +}: { + request: Request; + params: Params; +}) => { + if (request.method == "DELETE") { + const response = await fetch(`/api/subs/${username}/sets/${id}`, { + method: "DELETE", + }); + + return { ok: response.ok }; + } +}; + type FormOrderSetOrderAddOn = Omit & { id: number | string; _delete?: boolean; diff --git a/flask/vite/src/SubOrderSets.tsx b/flask/vite/src/SubOrderSets.tsx index d15be00..ef08d9a 100644 --- a/flask/vite/src/SubOrderSets.tsx +++ b/flask/vite/src/SubOrderSets.tsx @@ -8,9 +8,11 @@ import { Badge, } from "@mantine/core"; import { TimeValue } from "@mantine/dates"; -import { IconPencil, IconPlus } from "@tabler/icons-react"; +import { IconPencil, IconPlus, IconTrash } from "@tabler/icons-react"; import React from "react"; -import { Params, useLoaderData, useParams, useNavigate } from "react-router"; +import { Params, useLoaderData, useParams, useFetcher } from "react-router"; +import { ConfirmDialogButton } from "./ConfirmDialogButton"; +import { NavigateButton } from "./NavigateButton"; export const subOrderSetsLoader = async ({ params: { username }, @@ -18,24 +20,8 @@ export const subOrderSetsLoader = async ({ params: Params; }) => fetch(`/api/subs/${username}/sets`).then((response) => response.json()); -const NavigateButton: React.FC<{ - children: React.ReactNode; - to: string; -}> = ({ children, to }) => { - const navigate = useNavigate(); - - const handleClick = React.useCallback(() => { - navigate(to); - }, [to]); - - return ( - - ); -}; - export const SubOrderSets: React.FC = () => { + const fetcher = useFetcher(); const { username: sub_username } = useParams(); const orderSets = useLoaderData< (Pick< @@ -46,6 +32,16 @@ export const SubOrderSets: React.FC = () => { })[] >(); + const handleDelete = React.useCallback( + (id: number) => { + fetcher.submit(null, { + action: `/dashboard/subs/${sub_username}/${id}`, + method: "DELETE", + }); + }, + [fetcher], + ); + return ( @@ -77,7 +73,15 @@ export const SubOrderSets: React.FC = () => { ) : null} <Text mb="md">Orders: {orders.length}</Text> </Flex> - <Flex justify="end"> + <Flex gap="md" justify="end"> + <ConfirmDialogButton + buttonColor="red" + buttonText="Delete" + text={`Are you sure you want to delete ${name}?`} + onConfirm={() => handleDelete(id)} + > + <IconTrash /> + </ConfirmDialogButton> <NavigateButton to={`/dashboard/subs/${sub_username}/${id}`} > diff --git a/flask/vite/src/main.tsx b/flask/vite/src/main.tsx index bed3924..49e8e4c 100644 --- a/flask/vite/src/main.tsx +++ b/flask/vite/src/main.tsx @@ -17,7 +17,11 @@ import "@mantine/notifications/styles.css"; import { SubsList, subsListLoader } from "./SubsList"; import { SubOrderSets, subOrderSetsLoader } from "./SubOrderSets"; -import { SubOrderSet, subOrderSetLoader } from "./SubOrderSet"; +import { + SubOrderSet, + subOrderSetLoader, + subOrderSetAction, +} from "./SubOrderSet"; const theme = createTheme({ components: { @@ -64,6 +68,7 @@ const router = createBrowserRouter([ path: "dashboard/subs/:username/:set_id", Component: SubOrderSet, loader: subOrderSetLoader, + action: subOrderSetAction, }, ]);