Can delete a single inbox entry
This commit is contained in:
parent
07ee499742
commit
2f807b4c73
@ -69,4 +69,14 @@ export class InboxApi {
|
|||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete an inbox entry
|
||||||
|
*/
|
||||||
|
static async Delete(movement: InboxEntry): Promise<void> {
|
||||||
|
await APIClient.exec({
|
||||||
|
uri: `/inbox/${movement.id}`,
|
||||||
|
method: "DELETE",
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -377,7 +377,9 @@ function MovementsTable(p: {
|
|||||||
variant="standard"
|
variant="standard"
|
||||||
size="small"
|
size="small"
|
||||||
value={labelFilter}
|
value={labelFilter}
|
||||||
onChange={(e) => { setLabelFilter(e.target.value); }}
|
onChange={(e) => {
|
||||||
|
setLabelFilter(e.target.value);
|
||||||
|
}}
|
||||||
style={{ padding: "0px", flex: 1 }}
|
style={{ padding: "0px", flex: 1 }}
|
||||||
/>
|
/>
|
||||||
<span style={{ flex: 1 }}></span>
|
<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 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 { DataGrid, GridColDef, GridRowSelectionModel } from "@mui/x-data-grid";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { InboxApi, InboxEntry } from "../api/InboxApi";
|
import { InboxApi, InboxEntry } from "../api/InboxApi";
|
||||||
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
import { useAlert } from "../hooks/context_providers/AlertDialogProvider";
|
||||||
|
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
|
||||||
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
||||||
|
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
|
||||||
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
|
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
|
||||||
import { AmountWidget } from "../widgets/AmountWidget";
|
import { AmountWidget } from "../widgets/AmountWidget";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
@ -92,9 +105,38 @@ function InboxTable(p: {
|
|||||||
onReload: (skipEntries: boolean) => void;
|
onReload: (skipEntries: boolean) => void;
|
||||||
showMovements?: boolean;
|
showMovements?: boolean;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
|
const alert = useAlert();
|
||||||
|
const confirm = useConfirm();
|
||||||
|
const snackbar = useSnackbar();
|
||||||
|
const loadingMessage = useLoadingMessage();
|
||||||
|
|
||||||
const [rowSelectionModel, setRowSelectionModel] =
|
const [rowSelectionModel, setRowSelectionModel] =
|
||||||
React.useState<GridRowSelectionModel>([]);
|
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]>[] = [
|
const columns: GridColDef<(typeof p.entries)[number]>[] = [
|
||||||
{
|
{
|
||||||
field: "time",
|
field: "time",
|
||||||
@ -153,6 +195,23 @@ function InboxTable(p: {
|
|||||||
return <MovementWidget id={params.row.movement_id} />;
|
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 (
|
return (
|
||||||
@ -191,3 +250,42 @@ function InboxTable(p: {
|
|||||||
</div>
|
</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
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
marginLeft: "5px",
|
||||||
display: "inline-flex",
|
display: "inline-flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user