Can delete a single inbox entry
This commit is contained in:
		@@ -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",
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user