feat: add confirmation modal when deleting a storage

This commit is contained in:
2026-09-02 17:30:43 +02:00
parent 80fb79dedd
commit 6f3759d48d
4 changed files with 151 additions and 75 deletions
+91 -73
View File
@@ -8,6 +8,8 @@ import type { Storage } from "../misc/interfaces";
import { formatDate } from "../utils/uxFncs"; import { formatDate } from "../utils/uxFncs";
import { Mono } from "./Mono.tsx"; import { Mono } from "./Mono.tsx";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useState } from "react";
import { DeleteConfirmation } from "./modals/DeleteConfirmation.tsx";
interface StorageRowProps { interface StorageRowProps {
storage: Storage; storage: Storage;
@@ -17,6 +19,9 @@ interface StorageRowProps {
export const StorageRow = ({ storage, onError }: StorageRowProps) => { export const StorageRow = ({ storage, onError }: StorageRowProps) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [showModal, setShowModal] = useState<boolean>(false);
const [storageToDelete, setStorageToDelete] = useState<Storage | null>(null);
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const mutation = useMutation({ const mutation = useMutation({
@@ -28,6 +33,11 @@ export const StorageRow = ({ storage, onError }: StorageRowProps) => {
onError, onError,
}); });
const deleteStorageModalFnc = async (storage: Storage) => {
setStorageToDelete(storage);
setShowModal(true);
};
const deleteMutation = useMutation({ const deleteMutation = useMutation({
mutationFn: (uuid: string) => deleteStorage(uuid), mutationFn: (uuid: string) => deleteStorage(uuid),
onSuccess: () => { onSuccess: () => {
@@ -52,82 +62,90 @@ export const StorageRow = ({ storage, onError }: StorageRowProps) => {
(values.description ?? "") !== (storage.description ?? ""); (values.description ?? "") !== (storage.description ?? "");
return ( return (
<tr key={storage.uuid} className="align-top"> <>
<td className="px-6 py-5"> <DeleteConfirmation
<form.Field name="name"> open={showModal}
{(field) => ( setOpen={setShowModal}
<Input storage={storageToDelete}
value={field.state.value} deleteStorageByUUID={(uuid) => deleteMutation.mutateAsync(uuid)}
onChange={(e) => field.handleChange(e.target.value)} />
onBlur={field.handleBlur} <tr key={storage.uuid} className="align-top">
size="sm" <td className="px-6 py-5">
variant="outlined" <form.Field name="name">
className="rounded-xl shadow-none" {(field) => (
sx={{ <Input
bgcolor: "var(--joy-palette-background-level1)", value={field.state.value}
color: "var(--joy-palette-text-secondary)", onChange={(e) => field.handleChange(e.target.value)}
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)", onBlur={field.handleBlur}
}} size="sm"
/> variant="outlined"
)} className="rounded-xl shadow-none"
</form.Field> sx={{
</td> bgcolor: "var(--joy-palette-background-level1)",
<td className="px-6 py-5"> color: "var(--joy-palette-text-secondary)",
<form.Field name="description"> "--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
{(field) => ( }}
<Input />
value={field.state.value} )}
onChange={(e) => field.handleChange(e.target.value)} </form.Field>
onBlur={field.handleBlur} </td>
size="sm" <td className="px-6 py-5">
variant="outlined" <form.Field name="description">
className="rounded-xl shadow-none" {(field) => (
sx={{ <Input
bgcolor: "var(--joy-palette-background-level1)", value={field.state.value}
color: "var(--joy-palette-text-secondary)", onChange={(e) => field.handleChange(e.target.value)}
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)", onBlur={field.handleBlur}
}} size="sm"
/> variant="outlined"
)} className="rounded-xl shadow-none"
</form.Field> sx={{
</td> bgcolor: "var(--joy-palette-background-level1)",
<td color: "var(--joy-palette-text-secondary)",
className="px-6 py-5 text-sm" "--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
style={{ color: "var(--joy-palette-text-tertiary)" }} }}
> />
<Mono>{formatDate(storage.created_at)}</Mono> )}
</td> </form.Field>
<td </td>
className="px-6 py-5 text-sm" <td
style={{ color: "var(--joy-palette-text-tertiary)" }} className="px-6 py-5 text-sm"
> style={{ color: "var(--joy-palette-text-tertiary)" }}
<Mono>{formatDate(storage.updated_at)}</Mono> >
</td> <Mono>{formatDate(storage.created_at)}</Mono>
<td className="px-6 py-5 text-right"> </td>
<div className="flex flex-wrap justify-end gap-2"> <td
{isDirty && ( className="px-6 py-5 text-sm"
<Button style={{ color: "var(--joy-palette-text-tertiary)" }}
color="primary" >
onClick={form.handleSubmit} <Mono>{formatDate(storage.updated_at)}</Mono>
</td>
<td className="px-6 py-5 text-right">
<div className="flex flex-wrap justify-end gap-2">
{isDirty && (
<Button
color="primary"
onClick={form.handleSubmit}
disabled={mutation.isPending || deleteMutation.isPending}
size="sm"
className="rounded-xl"
>
{mutation.isPending ? "..." : t("save")}
</Button>
)}
<IconButton
color="danger"
variant="plain"
onClick={() => deleteStorageModalFnc(storage)}
disabled={mutation.isPending || deleteMutation.isPending} disabled={mutation.isPending || deleteMutation.isPending}
size="sm" size="sm"
className="rounded-xl" className="rounded-xl"
> >
{mutation.isPending ? "..." : t("save")} <Trash2 size={16} />
</Button> </IconButton>
)} </div>
<IconButton </td>
color="danger" </tr>
variant="plain" </>
onClick={() => deleteMutation.mutateAsync(storage.uuid)}
disabled={mutation.isPending || deleteMutation.isPending}
size="sm"
className="rounded-xl"
>
<Trash2 size={16} />
</IconButton>
</div>
</td>
</tr>
); );
}; };
@@ -0,0 +1,54 @@
import Button from "@mui/joy/Button";
import Divider from "@mui/joy/Divider";
import DialogTitle from "@mui/joy/DialogTitle";
import DialogContent from "@mui/joy/DialogContent";
import DialogActions from "@mui/joy/DialogActions";
import Modal from "@mui/joy/Modal";
import ModalDialog from "@mui/joy/ModalDialog";
import type { Storage } from "../../misc/interfaces";
import { useTranslation } from "react-i18next";
interface DeleteConfirmationProps {
open: boolean;
setOpen: (open: boolean) => void;
storage: Storage | null;
deleteStorageByUUID: (uuid: string) => void;
}
export const DeleteConfirmation = (props: DeleteConfirmationProps) => {
const { t } = useTranslation();
return (
<Modal open={props.open} onClose={() => props.setOpen(false)}>
<ModalDialog variant="outlined" role="alertdialog">
<DialogTitle>Confirmation</DialogTitle>
<Divider />
<DialogContent>
{t("delete-confirmation-text")}
{props.storage ? ` "${props.storage.name}"` : ""}?
</DialogContent>
<DialogActions>
<Button
variant="solid"
color="danger"
onClick={() => {
if (props.storage) {
props.deleteStorageByUUID(props.storage.uuid);
}
props.setOpen(false);
}}
>
{t("delete")}
</Button>
<Button
variant="plain"
color="neutral"
onClick={() => props.setOpen(false)}
>
{t("cancel")}
</Button>
</DialogActions>
</ModalDialog>
</Modal>
);
};
+3 -1
View File
@@ -129,5 +129,7 @@
"filter-soon": "Bald", "filter-soon": "Bald",
"filter-low": "Niedrig", "filter-low": "Niedrig",
"products": "Produkte", "products": "Produkte",
"units": "Einheiten" "units": "Einheiten",
"cancel": "Abbrechen",
"delete-confirmation-text": "Bist du dir sicher das du diesen Storage löschen willst: "
} }
+3 -1
View File
@@ -129,5 +129,7 @@
"filter-soon": "Soon", "filter-soon": "Soon",
"filter-low": "Low", "filter-low": "Low",
"products": "products", "products": "products",
"units": "units" "units": "units",
"cancel": "Cancel",
"delete-confirmation-text": "Are you sure you want to delete this storage: "
} }