feat: add confirmation modal when deleting a storage
This commit is contained in:
@@ -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>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -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: "
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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: "
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user