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 { Mono } from "./Mono.tsx";
import { useTranslation } from "react-i18next";
import { useState } from "react";
import { DeleteConfirmation } from "./modals/DeleteConfirmation.tsx";
interface StorageRowProps {
storage: Storage;
@@ -17,6 +19,9 @@ interface StorageRowProps {
export const StorageRow = ({ storage, onError }: StorageRowProps) => {
const { t } = useTranslation();
const [showModal, setShowModal] = useState<boolean>(false);
const [storageToDelete, setStorageToDelete] = useState<Storage | null>(null);
const queryClient = useQueryClient();
const mutation = useMutation({
@@ -28,6 +33,11 @@ export const StorageRow = ({ storage, onError }: StorageRowProps) => {
onError,
});
const deleteStorageModalFnc = async (storage: Storage) => {
setStorageToDelete(storage);
setShowModal(true);
};
const deleteMutation = useMutation({
mutationFn: (uuid: string) => deleteStorage(uuid),
onSuccess: () => {
@@ -52,82 +62,90 @@ export const StorageRow = ({ storage, onError }: StorageRowProps) => {
(values.description ?? "") !== (storage.description ?? "");
return (
<tr key={storage.uuid} className="align-top">
<td className="px-6 py-5">
<form.Field name="name">
{(field) => (
<Input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
size="sm"
variant="outlined"
className="rounded-xl shadow-none"
sx={{
bgcolor: "var(--joy-palette-background-level1)",
color: "var(--joy-palette-text-secondary)",
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
}}
/>
)}
</form.Field>
</td>
<td className="px-6 py-5">
<form.Field name="description">
{(field) => (
<Input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
size="sm"
variant="outlined"
className="rounded-xl shadow-none"
sx={{
bgcolor: "var(--joy-palette-background-level1)",
color: "var(--joy-palette-text-secondary)",
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
}}
/>
)}
</form.Field>
</td>
<td
className="px-6 py-5 text-sm"
style={{ color: "var(--joy-palette-text-tertiary)" }}
>
<Mono>{formatDate(storage.created_at)}</Mono>
</td>
<td
className="px-6 py-5 text-sm"
style={{ color: "var(--joy-palette-text-tertiary)" }}
>
<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}
<>
<DeleteConfirmation
open={showModal}
setOpen={setShowModal}
storage={storageToDelete}
deleteStorageByUUID={(uuid) => deleteMutation.mutateAsync(uuid)}
/>
<tr key={storage.uuid} className="align-top">
<td className="px-6 py-5">
<form.Field name="name">
{(field) => (
<Input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
size="sm"
variant="outlined"
className="rounded-xl shadow-none"
sx={{
bgcolor: "var(--joy-palette-background-level1)",
color: "var(--joy-palette-text-secondary)",
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
}}
/>
)}
</form.Field>
</td>
<td className="px-6 py-5">
<form.Field name="description">
{(field) => (
<Input
value={field.state.value}
onChange={(e) => field.handleChange(e.target.value)}
onBlur={field.handleBlur}
size="sm"
variant="outlined"
className="rounded-xl shadow-none"
sx={{
bgcolor: "var(--joy-palette-background-level1)",
color: "var(--joy-palette-text-secondary)",
"--Input-focusedHighlight": "var(--joy-palette-neutral-300)",
}}
/>
)}
</form.Field>
</td>
<td
className="px-6 py-5 text-sm"
style={{ color: "var(--joy-palette-text-tertiary)" }}
>
<Mono>{formatDate(storage.created_at)}</Mono>
</td>
<td
className="px-6 py-5 text-sm"
style={{ color: "var(--joy-palette-text-tertiary)" }}
>
<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}
size="sm"
className="rounded-xl"
>
{mutation.isPending ? "..." : t("save")}
</Button>
)}
<IconButton
color="danger"
variant="plain"
onClick={() => deleteMutation.mutateAsync(storage.uuid)}
disabled={mutation.isPending || deleteMutation.isPending}
size="sm"
className="rounded-xl"
>
<Trash2 size={16} />
</IconButton>
</div>
</td>
</tr>
<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-low": "Niedrig",
"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-low": "Low",
"products": "products",
"units": "units"
"units": "units",
"cancel": "Cancel",
"delete-confirmation-text": "Are you sure you want to delete this storage: "
}