Display the list of inbox entries
This commit is contained in:
parent
e55b99b264
commit
76f9e37ded
@ -54,4 +54,19 @@ export class InboxApi {
|
|||||||
})
|
})
|
||||||
).data;
|
).data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update inbox entry
|
||||||
|
*/
|
||||||
|
static async Update(
|
||||||
|
inbox: InboxEntry & InboxEntryUpdate
|
||||||
|
): Promise<InboxEntry> {
|
||||||
|
return (
|
||||||
|
await APIClient.exec({
|
||||||
|
uri: `/inbox/${inbox.id}`,
|
||||||
|
method: "PUT",
|
||||||
|
jsonData: inbox,
|
||||||
|
})
|
||||||
|
).data;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
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, Tooltip } from "@mui/material";
|
||||||
|
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 { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
|
||||||
|
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
|
||||||
|
import { AmountWidget } from "../widgets/AmountWidget";
|
||||||
import { AsyncWidget } from "../widgets/AsyncWidget";
|
import { AsyncWidget } from "../widgets/AsyncWidget";
|
||||||
|
import { DateWidget } from "../widgets/DateWidget";
|
||||||
import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer";
|
import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer";
|
||||||
import { NewMovementWidget } from "../widgets/NewMovementWidget";
|
import { NewMovementWidget } from "../widgets/NewMovementWidget";
|
||||||
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
|
import { UploadedFileWidget } from "../widgets/UploadedFileWidget";
|
||||||
|
|
||||||
export function InboxRoute(): React.ReactElement {
|
export function InboxRoute(): React.ReactElement {
|
||||||
const loadingMessage = useLoadingMessage();
|
const loadingMessage = useLoadingMessage();
|
||||||
@ -46,9 +50,8 @@ export function InboxRoute(): React.ReactElement {
|
|||||||
checked={includeAttached}
|
checked={includeAttached}
|
||||||
control={
|
control={
|
||||||
<Checkbox
|
<Checkbox
|
||||||
onChange={(e) => {
|
onChange={(_e, value) => {
|
||||||
setIncludeAttached(e.target.checked);
|
setIncludeAttached(value);
|
||||||
reload(false);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
@ -65,10 +68,10 @@ export function InboxRoute(): React.ReactElement {
|
|||||||
<div style={{ display: "flex", flexDirection: "column", flex: 1 }}>
|
<div style={{ display: "flex", flexDirection: "column", flex: 1 }}>
|
||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||||
<AsyncWidget
|
<AsyncWidget
|
||||||
loadKey={loadKey.current}
|
loadKey={loadKey.current + String(includeAttached)}
|
||||||
load={load}
|
load={load}
|
||||||
errMsg="Failed to load the content of inbox!"
|
errMsg="Failed to load the content of inbox!"
|
||||||
build={() => <>todo table</>}
|
build={() => <InboxTable entries={entries!} onReload={reload} />}
|
||||||
/>
|
/>
|
||||||
<NewMovementWidget isInbox onCreated={() => reload(false)} />
|
<NewMovementWidget isInbox onCreated={() => reload(false)} />
|
||||||
</div>
|
</div>
|
||||||
@ -76,3 +79,97 @@ export function InboxRoute(): React.ReactElement {
|
|||||||
</MoneyMgrWebRouteContainer>
|
</MoneyMgrWebRouteContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function InboxTable(p: {
|
||||||
|
entries: InboxEntry[];
|
||||||
|
onReload: (skipEntries: boolean) => void;
|
||||||
|
}): React.ReactElement {
|
||||||
|
const [rowSelectionModel, setRowSelectionModel] =
|
||||||
|
React.useState<GridRowSelectionModel>([]);
|
||||||
|
|
||||||
|
const columns: GridColDef<(typeof p.entries)[number]>[] = [
|
||||||
|
{
|
||||||
|
field: "time",
|
||||||
|
headerName: "Date",
|
||||||
|
width: 98 + 80,
|
||||||
|
editable: true,
|
||||||
|
type: "dateTime",
|
||||||
|
valueGetter(_, m) {
|
||||||
|
return new Date(m.time * 1000);
|
||||||
|
},
|
||||||
|
valueSetter(v, row) {
|
||||||
|
row.time = Math.floor(v.getTime() / 1000);
|
||||||
|
return row;
|
||||||
|
},
|
||||||
|
renderCell: (params) => {
|
||||||
|
return <DateWidget time={params.row.time} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "label",
|
||||||
|
headerName: "Label",
|
||||||
|
flex: 3,
|
||||||
|
editable: true,
|
||||||
|
type: "string",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "amount",
|
||||||
|
headerName: "Amount",
|
||||||
|
width: 110,
|
||||||
|
editable: true,
|
||||||
|
type: "number",
|
||||||
|
align: "left",
|
||||||
|
headerAlign: "left",
|
||||||
|
renderCell: (params) => {
|
||||||
|
if (params.row.amount)
|
||||||
|
return <AmountWidget amount={params.row.amount} />;
|
||||||
|
else return <i>Unspecified</i>;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: "file",
|
||||||
|
headerName: "File",
|
||||||
|
editable: false,
|
||||||
|
flex: 3,
|
||||||
|
renderCell: (params) => {
|
||||||
|
return <UploadedFileWidget file_id={params.row.file_id} />;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<DataGrid<InboxEntry>
|
||||||
|
columns={columns}
|
||||||
|
rows={p.entries}
|
||||||
|
autoPageSize
|
||||||
|
checkboxSelection
|
||||||
|
initialState={{
|
||||||
|
sorting: {
|
||||||
|
sortModel: [{ field: "time", sort: "desc" }],
|
||||||
|
},
|
||||||
|
columns: {
|
||||||
|
columnVisibilityModel: {
|
||||||
|
checked: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onRowSelectionModelChange={(newRowSelectionModel) => {
|
||||||
|
setRowSelectionModel(newRowSelectionModel);
|
||||||
|
}}
|
||||||
|
rowSelectionModel={rowSelectionModel}
|
||||||
|
processRowUpdate={async (n) => {
|
||||||
|
try {
|
||||||
|
return await InboxApi.Update(n);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to update movement information!", e);
|
||||||
|
alert(`Failed to update row! ${e}`);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
p.onReload(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user