204 lines
5.5 KiB
TypeScript
204 lines
5.5 KiB
TypeScript
import AddIcon from "@mui/icons-material/Add";
|
|
import {
|
|
Fab,
|
|
ListItem,
|
|
ListItemButton,
|
|
Paper,
|
|
Tooltip,
|
|
Typography,
|
|
} from "@mui/material";
|
|
import React from "react";
|
|
import { Movement, MovementApi } from "../api/MovementsApi";
|
|
import { UpdateMovementDialog } from "../dialogs/UpdateMovementDialog";
|
|
import { AsyncWidget } from "./AsyncWidget";
|
|
import { AccountInput } from "./forms/AccountInput";
|
|
import { AmountInput } from "./forms/AmountInput";
|
|
import { DateInput } from "./forms/DateInput";
|
|
import { TextInput } from "./forms/TextInput";
|
|
import { MovementWidget } from "./MovementWidget";
|
|
|
|
export function SelectMovementWidget(p: {
|
|
value?: number;
|
|
onChange: (movement: Movement) => void;
|
|
initialValues?: {
|
|
amount?: number;
|
|
accountId?: number;
|
|
time?: number;
|
|
label?: string;
|
|
};
|
|
}): React.ReactElement {
|
|
const loadKey = React.useRef(1);
|
|
|
|
const [amount, setAmount] = React.useState<number | undefined>(
|
|
p.initialValues?.amount
|
|
);
|
|
const [accountId, setAccountId] = React.useState<number | undefined>(
|
|
p.initialValues?.accountId
|
|
);
|
|
const [time, setTime] = React.useState<number | undefined>(
|
|
p.initialValues?.time
|
|
);
|
|
const [label, setLabel] = React.useState<string | undefined>(
|
|
p.initialValues?.label
|
|
);
|
|
|
|
const filters = {
|
|
label: label,
|
|
amount_min: amount ? amount - 0.5 : undefined,
|
|
amount_max: amount ? amount + 0.5 : undefined,
|
|
time_min: time ? time - 3600 * 24 : undefined,
|
|
time_max: time ? time + 3600 * 24 : undefined,
|
|
limit: 10,
|
|
};
|
|
|
|
const [list, setList] = React.useState<Movement[] | undefined>();
|
|
|
|
const load = async () => {
|
|
if (accountId)
|
|
setList(await MovementApi.GetAccountMovements(accountId, filters));
|
|
else setList(undefined);
|
|
};
|
|
|
|
const [creating, setCreating] = React.useState(false);
|
|
|
|
const handleStartCreateNewMovement = () => {
|
|
setCreating(true);
|
|
};
|
|
|
|
const handleCloseCreateNewMovement = () => {
|
|
setCreating(false);
|
|
};
|
|
|
|
const handleCreatedNewMovement = (m: Movement) => {
|
|
setAmount(m.amount);
|
|
setAccountId(m.account_id);
|
|
setTime(m.time);
|
|
setLabel(m.label);
|
|
p.onChange(m);
|
|
loadKey.current += 1;
|
|
setCreating(false);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Paper
|
|
style={{
|
|
padding: "10px",
|
|
flex: 1,
|
|
display: "flex",
|
|
flexDirection: "column",
|
|
}}
|
|
>
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
}}
|
|
>
|
|
<AccountInput
|
|
value={accountId}
|
|
onChange={setAccountId}
|
|
style={{ flex: 20 }}
|
|
/>
|
|
<span style={{ flex: 1 }} />
|
|
<AmountInput
|
|
editable
|
|
value={amount ?? 0}
|
|
onValueChange={setAmount}
|
|
label="Amount"
|
|
placeholder="Amount"
|
|
variant="outlined"
|
|
style={{ height: "100%", flex: 20 }}
|
|
/>
|
|
<span style={{ flex: 1 }} />
|
|
<DateInput
|
|
editable
|
|
value={time}
|
|
onValueChange={setTime}
|
|
label="Date"
|
|
style={{ flex: 20 }}
|
|
variant="outlined"
|
|
/>
|
|
<span style={{ flex: 1 }} />
|
|
<TextInput
|
|
editable
|
|
value={label}
|
|
onValueChange={setLabel}
|
|
label="Label"
|
|
variant="outlined"
|
|
style={{ flex: 20 }}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ flex: 1 }}>
|
|
<AsyncWidget
|
|
loadKey={`${loadKey.current}/${accountId}/${JSON.stringify(
|
|
filters
|
|
)}`}
|
|
load={load}
|
|
errMsg="Failed to load the list of movements!"
|
|
build={() => {
|
|
if (list === undefined)
|
|
return (
|
|
<Typography style={{ textAlign: "center", padding: "20px" }}>
|
|
Select an account to begin research.
|
|
</Typography>
|
|
);
|
|
if (list.length === 0)
|
|
return (
|
|
<Typography style={{ textAlign: "center", padding: "20px" }}>
|
|
No result.
|
|
</Typography>
|
|
);
|
|
|
|
return (
|
|
<>
|
|
{list.map((entry) => (
|
|
<ListItem key={entry.id}>
|
|
<ListItemButton
|
|
selected={entry.id === p.value}
|
|
onClick={() => {
|
|
p.onChange(entry);
|
|
}}
|
|
>
|
|
<MovementWidget movement={entry} />
|
|
</ListItemButton>
|
|
</ListItem>
|
|
))}
|
|
</>
|
|
);
|
|
}}
|
|
/>
|
|
</div>
|
|
|
|
<div style={{ textAlign: "right" }}>
|
|
<Tooltip title="Create a new movement">
|
|
<Fab
|
|
color="primary"
|
|
aria-label="Create a new movement"
|
|
onClick={handleStartCreateNewMovement}
|
|
>
|
|
<AddIcon />
|
|
</Fab>
|
|
</Tooltip>
|
|
</div>
|
|
</Paper>
|
|
{creating && accountId && (
|
|
<UpdateMovementDialog
|
|
open
|
|
initial={{
|
|
account_id: accountId,
|
|
amount: amount ?? 0,
|
|
checked: false,
|
|
label: label ?? "",
|
|
time: time ?? 0,
|
|
}}
|
|
onClose={handleCloseCreateNewMovement}
|
|
onFinished={handleCreatedNewMovement}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
}
|