Can delete multiple movements

This commit is contained in:
Pierre HUBERT 2025-04-23 20:55:52 +02:00
parent 53494210af
commit a24eb02dc4
2 changed files with 115 additions and 36 deletions

View File

@ -9,7 +9,7 @@ import {
import React, { PropsWithChildren } from "react"; import React, { PropsWithChildren } from "react";
type ConfirmContext = ( type ConfirmContext = (
message: string, message: string | React.ReactElement,
title?: string, title?: string,
confirmButton?: string confirmButton?: string
) => Promise<boolean>; ) => Promise<boolean>;
@ -22,7 +22,7 @@ export function ConfirmDialogProvider(
const [open, setOpen] = React.useState(false); const [open, setOpen] = React.useState(false);
const [title, setTitle] = React.useState<string | undefined>(undefined); const [title, setTitle] = React.useState<string | undefined>(undefined);
const [message, setMessage] = React.useState(""); const [message, setMessage] = React.useState<string | React.ReactElement>("");
const [confirmButton, setConfirmButton] = React.useState<string | undefined>( const [confirmButton, setConfirmButton] = React.useState<string | undefined>(
undefined undefined
); );
@ -53,13 +53,13 @@ export function ConfirmDialogProvider(
return ( return (
<> <>
<ConfirmContextK value={hook}> <ConfirmContextK value={hook}>{p.children}</ConfirmContextK>
{p.children}
</ConfirmContextK>
<Dialog <Dialog
open={open} open={open}
onClose={() => { handleClose(false); }} onClose={() => {
handleClose(false);
}}
aria-labelledby="alert-dialog-title" aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description" aria-describedby="alert-dialog-description"
onKeyUp={keyUp} onKeyUp={keyUp}
@ -71,10 +71,20 @@ export function ConfirmDialogProvider(
</DialogContentText> </DialogContentText>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={() => { handleClose(false); }} autoFocus> <Button
onClick={() => {
handleClose(false);
}}
autoFocus
>
Cancel Cancel
</Button> </Button>
<Button onClick={() => { handleClose(true); }} color="error"> <Button
onClick={() => {
handleClose(true);
}}
color="error"
>
{confirmButton ?? "Confirm"} {confirmButton ?? "Confirm"}
</Button> </Button>
</DialogActions> </DialogActions>

View File

@ -1,7 +1,12 @@
import DeleteIcon from "@mui/icons-material/DeleteOutlined"; import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import DriveFileMoveOutlineIcon from "@mui/icons-material/DriveFileMoveOutline"; import DriveFileMoveOutlineIcon from "@mui/icons-material/DriveFileMoveOutline";
import { Tooltip, Typography } from "@mui/material"; import { IconButton, Tooltip, Typography } from "@mui/material";
import { DataGrid, GridActionsCellItem, GridColDef } from "@mui/x-data-grid"; import {
DataGrid,
GridActionsCellItem,
GridColDef,
GridRowSelectionModel,
} from "@mui/x-data-grid";
import React from "react"; import React from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { Movement, MovementApi } from "../api/MovementsApi"; import { Movement, MovementApi } from "../api/MovementsApi";
@ -93,9 +98,13 @@ function MovementsTable(p: {
const alert = useAlert(); const alert = useAlert();
const confirm = useConfirm(); const confirm = useConfirm();
const snackbar = useSnackbar(); const snackbar = useSnackbar();
const loadingMessage = useLoadingMessage();
const chooseAccount = useSelectAccount(); const chooseAccount = useSelectAccount();
const [rowSelectionModel, setRowSelectionModel] =
React.useState<GridRowSelectionModel>([]);
// Change account of movement // Change account of movement
const handleMoveClick = async (movement: Movement) => { const handleMoveClick = async (movement: Movement) => {
const target = await chooseAccount( const target = await chooseAccount(
@ -143,6 +152,46 @@ function MovementsTable(p: {
} }
}; };
// Delete multiple movements
const deleteMultiple = async () => {
try {
const movements = p.movements.filter((m) =>
rowSelectionModel.includes(m.id)
);
if (
!(await confirm(
<>
Do you really want to delete the following movements:
<ul>
{movements.map((m) => (
<li>
{m.label} ({m.amount} )
</li>
))}
</ul>
</>
))
)
return;
for (const [num, m] of movements.entries()) {
loadingMessage.show(`Deleting movement ${num}/${movements.length}`);
await MovementApi.Delete(m);
}
snackbar("The movements have been successfully deleted!");
p.needReload(false);
} catch (e) {
console.error("Failed to delete multiple movements!", e);
alert(`Failed to delete multiple movements! ${e}`);
} finally {
loadingMessage.hide();
}
};
const columns: GridColDef<(typeof p.movements)[number]>[] = [ const columns: GridColDef<(typeof p.movements)[number]>[] = [
{ {
field: "checked", field: "checked",
@ -221,7 +270,22 @@ function MovementsTable(p: {
}, },
}, },
]; ];
return ( return (
<>
<div>
<Tooltip title="Delete all the selected entries">
<IconButton
disabled={
rowSelectionModel.length === 0 ||
rowSelectionModel.length === p.movements.length
}
onClick={deleteMultiple}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</div>
<DataGrid<Movement> <DataGrid<Movement>
columns={columns} columns={columns}
rows={p.movements} rows={p.movements}
@ -237,6 +301,10 @@ function MovementsTable(p: {
}, },
}, },
}} }}
onRowSelectionModelChange={(newRowSelectionModel) => {
setRowSelectionModel(newRowSelectionModel);
}}
rowSelectionModel={rowSelectionModel}
processRowUpdate={async (n) => { processRowUpdate={async (n) => {
try { try {
return await MovementApi.Update(n); return await MovementApi.Update(n);
@ -249,5 +317,6 @@ function MovementsTable(p: {
} }
}} }}
/> />
</>
); );
} }