Can delete a single inbox entry
This commit is contained in:
parent
07ee499742
commit
2f807b4c73
@ -69,4 +69,14 @@ export class InboxApi {
|
||||
})
|
||||
).data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete an inbox entry
|
||||
*/
|
||||
static async Delete(movement: InboxEntry): Promise<void> {
|
||||
await APIClient.exec({
|
||||
uri: `/inbox/${movement.id}`,
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +167,7 @@ function MovementsTable(p: {
|
||||
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!`,
|
||||
`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`
|
||||
))
|
||||
@ -186,7 +186,7 @@ function MovementsTable(p: {
|
||||
try {
|
||||
if (
|
||||
!(await confirm(
|
||||
`Do you really want to delete the movement ${movement.label} (${movement.amount}€)?`
|
||||
`Do you really want to delete the movement ${movement.label} (${movement.amount} €)?`
|
||||
))
|
||||
)
|
||||
return;
|
||||
@ -377,7 +377,9 @@ function MovementsTable(p: {
|
||||
variant="standard"
|
||||
size="small"
|
||||
value={labelFilter}
|
||||
onChange={(e) => { setLabelFilter(e.target.value); }}
|
||||
onChange={(e) => {
|
||||
setLabelFilter(e.target.value);
|
||||
}}
|
||||
style={{ padding: "0px", flex: 1 }}
|
||||
/>
|
||||
<span style={{ flex: 1 }}></span>
|
||||
|
@ -1,10 +1,23 @@
|
||||
import DeleteIcon from "@mui/icons-material/DeleteOutlined";
|
||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||
import RefreshIcon from "@mui/icons-material/Refresh";
|
||||
import { Checkbox, FormControlLabel, IconButton, Tooltip } from "@mui/material";
|
||||
import {
|
||||
Checkbox,
|
||||
FormControlLabel,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Menu,
|
||||
MenuItem,
|
||||
Tooltip,
|
||||
} from "@mui/material";
|
||||
import { DataGrid, GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
|
||||
import React from "react";
|
||||
import { InboxApi, InboxEntry } from "../api/InboxApi";
|
||||
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
||||
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
||||
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
||||
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
||||
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
|
||||
import { AmountWidget } from "../widgets/AmountWidget";
|
||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||
@ -92,9 +105,38 @@ function InboxTable(p: {
|
||||
onReload: (skipEntries: boolean) => void;
|
||||
showMovements?: boolean;
|
||||
}): React.ReactElement {
|
||||
const alert = useAlert();
|
||||
const confirm = useConfirm();
|
||||
const snackbar = useSnackbar();
|
||||
const loadingMessage = useLoadingMessage();
|
||||
|
||||
const [rowSelectionModel, setRowSelectionModel] =
|
||||
React.useState<GridRowSelectionModel>([]);
|
||||
|
||||
// Delete inbox entry
|
||||
const handleDeleteClick = async (entry: InboxEntry) => {
|
||||
try {
|
||||
if (
|
||||
!(await confirm(
|
||||
`Do you really want to delete this inbox entry ${
|
||||
entry.label ?? ""
|
||||
} (${entry.amount ?? 0} €)?`
|
||||
))
|
||||
)
|
||||
return;
|
||||
|
||||
await InboxApi.Delete(entry);
|
||||
|
||||
const id = p.entries.findIndex((m) => entry.id === m.id);
|
||||
p.entries.slice(id, id);
|
||||
|
||||
p.onReload(false);
|
||||
} catch (e) {
|
||||
console.error("Failed to delete movement!", e);
|
||||
alert(`Failed to delete movement! ${e}`);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: GridColDef<(typeof p.entries)[number]>[] = [
|
||||
{
|
||||
field: "time",
|
||||
@ -153,6 +195,23 @@ function InboxTable(p: {
|
||||
return <MovementWidget id={params.row.movement_id} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: "actions",
|
||||
type: "actions",
|
||||
headerName: "",
|
||||
width: 55,
|
||||
cellClassName: "actions",
|
||||
editable: false,
|
||||
getActions: (params) => {
|
||||
return [
|
||||
<InboxEntryActionMenu
|
||||
key="menu"
|
||||
movement={params.row}
|
||||
onDelete={handleDeleteClick}
|
||||
/>,
|
||||
];
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
@ -191,3 +250,42 @@ function InboxTable(p: {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function InboxEntryActionMenu(p: {
|
||||
movement: InboxEntry;
|
||||
onDelete: (entry: InboxEntry) => 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}>
|
||||
{/* Delete */}
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
handleClose();
|
||||
p.onDelete(p.movement);
|
||||
}}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<DeleteIcon color="error" />
|
||||
</ListItemIcon>
|
||||
<ListItemText secondary={"Delete the entry"}>Delete</ListItemText>
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ export function MovementWidget(p: { id: number }): React.ReactElement {
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
marginLeft: "5px",
|
||||
display: "inline-flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
|
Loading…
x
Reference in New Issue
Block a user