Can detach file from movement

This commit is contained in:
Pierre HUBERT 2025-05-01 18:38:22 +02:00
parent a5609d2ebd
commit bce17bc9b4

View File

@ -1,14 +1,20 @@
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import DriveFileMoveOutlineIcon from "@mui/icons-material/DriveFileMoveOutline";
import { IconButton, Tooltip, Typography } from "@mui/material";
import LinkOffIcon from "@mui/icons-material/LinkOff";
import MoreVertIcon from "@mui/icons-material/MoreVert";
import {
DataGrid,
GridActionsCellItem,
GridColDef,
GridRowSelectionModel,
} from "@mui/x-data-grid";
IconButton,
ListItemIcon,
ListItemText,
Tooltip,
Typography,
} from "@mui/material";
import Menu from "@mui/material/Menu";
import MenuItem from "@mui/material/MenuItem";
import { DataGrid, GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
import React from "react";
import { useParams } from "react-router-dom";
import { UploadedFile } from "../api/FileApi";
import { Movement, MovementApi } from "../api/MovementsApi";
import { useAccounts } from "../hooks/AccountsListProvider";
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
@ -20,12 +26,11 @@ import { AccountWidget } from "../widgets/AccountWidget";
import { AmountWidget } from "../widgets/AmountWidget";
import { AsyncWidget } from "../widgets/AsyncWidget";
import { DateWidget } from "../widgets/DateWidget";
import { UploadFileButton } from "../widgets/forms/UploadFileButton";
import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer";
import { NewMovementWidget } from "../widgets/NewMovementWidget";
import { NotFoundRoute } from "./NotFound";
import { UploadFileButton } from "../widgets/forms/UploadFileButton";
import { UploadedFile } from "../api/FileApi";
import { UploadedFileWidget } from "../widgets/UploadedFileWidget";
import { NotFoundRoute } from "./NotFound";
export function AccountRoute(): React.ReactElement {
const loadingMessage = useLoadingMessage();
@ -80,7 +85,7 @@ export function AccountRoute(): React.ReactElement {
<AsyncWidget
loadKey={`${account.id}-${loadKey.current}`}
load={load}
ready={movements}
ready={movements !== undefined}
errMsg="Failed to load the list of movements!"
build={() => (
<MovementsTable needReload={reload} movements={movements!} />
@ -148,6 +153,25 @@ function MovementsTable(p: {
}
};
// Detach movement from account
const handleDetachFile = async (movement: Movement) => {
try {
if (
!(await confirm(
`Do you really want to detach the file attached to the movement ${movement.label} (${movement.amount}€)? The associated file will be automatically deleted within the day if it is not referenced anywhere else!`,
`Detach file from movement`,
`Detach file`
))
)
return;
await setUploadedFile(movement, undefined);
} catch (e) {
console.error("Failed to detach file from movement!", e);
alert(`Failed to detach file from movement! ${e}`);
}
};
// Delete movement
const handleDeleteClick = async (movement: Movement) => {
try {
@ -318,28 +342,19 @@ function MovementsTable(p: {
{
field: "actions",
type: "actions",
headerName: "Actions",
width: 80,
headerName: "",
width: 55,
cellClassName: "actions",
editable: false,
getActions: (params) => {
return [
<Tooltip title="Move to another account" key="move">
<GridActionsCellItem
icon={<DriveFileMoveOutlineIcon />}
label="Move to another account"
onClick={() => handleMoveClick(params.row)}
color="inherit"
/>
</Tooltip>,
<Tooltip title="Delete the movement" key="delete">
<GridActionsCellItem
icon={<DeleteIcon color="error" />}
label="Delete"
onClick={() => handleDeleteClick(params.row)}
color="inherit"
/>
</Tooltip>,
<MovementActionMenu
key="menu"
movement={params.row}
onDelete={handleDeleteClick}
onMove={handleMoveClick}
onDetachFile={handleDetachFile}
/>,
];
},
},
@ -407,3 +422,74 @@ function MovementsTable(p: {
</>
);
}
function MovementActionMenu(p: {
movement: Movement;
onDetachFile: (m: Movement) => void;
onMove: (m: Movement) => void;
onDelete: (m: Movement) => void;
}): React.ReactElement {
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
const open = Boolean(anchorEl);
const handleClick = (event: React.MouseEvent<HTMLElement>) => {
setAnchorEl(event.currentTarget);
};
const handleClose = () => {
setAnchorEl(null);
};
return (
<>
<IconButton
aria-label="Actions"
aria-haspopup="true"
onClick={handleClick}
>
<MoreVertIcon />
</IconButton>
<Menu anchorEl={anchorEl} open={open} onClose={handleClose}>
{/* Detach file */}
{p.movement.file_id && (
<MenuItem
onClick={() => {
handleClose();
p.onDetachFile(p.movement);
}}
>
<ListItemIcon>
<LinkOffIcon />
</ListItemIcon>
<ListItemText secondary={"Detach linked file"}>
Detach file
</ListItemText>
</MenuItem>
)}
{/* Move to another account */}
<MenuItem
onClick={() => {
handleClose();
p.onMove(p.movement);
}}
>
<ListItemIcon>
<DriveFileMoveOutlineIcon />
</ListItemIcon>
<ListItemText secondary={"Move to another account"}>
Move
</ListItemText>
</MenuItem>
{/* Delete */}
<MenuItem
onClick={() => {
handleClose();
p.onDelete(p.movement);
}}
>
<ListItemIcon>
<DeleteIcon color="error" />
</ListItemIcon>
<ListItemText secondary={"Delete the movement"}>Delete</ListItemText>
</MenuItem>
</Menu>
</>
);
}