Created a dialog to select an account
This commit is contained in:
parent
2afedcd5f9
commit
639fa4b176
82
moneymgr_web/src/dialogs/SelectAccountDialog.tsx
Normal file
82
moneymgr_web/src/dialogs/SelectAccountDialog.tsx
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Dialog,
|
||||||
|
DialogActions,
|
||||||
|
DialogContent,
|
||||||
|
DialogContentText,
|
||||||
|
DialogTitle,
|
||||||
|
FormControlLabel,
|
||||||
|
ListItem,
|
||||||
|
ListItemIcon,
|
||||||
|
ListItemText,
|
||||||
|
Radio,
|
||||||
|
RadioGroup,
|
||||||
|
} from "@mui/material";
|
||||||
|
import React from "react";
|
||||||
|
import { Account } from "../api/AccountApi";
|
||||||
|
import { useAccounts } from "../hooks/AccountsListProvider";
|
||||||
|
import { AccountWidget } from "../widgets/AccountWidget";
|
||||||
|
import { AmountWidget } from "../widgets/AmountWidget";
|
||||||
|
|
||||||
|
export function SelectAccountDialog(p: {
|
||||||
|
open: boolean;
|
||||||
|
onClose: () => void;
|
||||||
|
onSelected: (c: Account) => void;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
confirmButton?: string;
|
||||||
|
excludedAccounts?: Account[];
|
||||||
|
}): React.ReactElement {
|
||||||
|
const accounts = useAccounts();
|
||||||
|
|
||||||
|
const [choice, setChoice] = React.useState<Account | null>(null);
|
||||||
|
console.log(choice);
|
||||||
|
const submit = () => {
|
||||||
|
if (choice) p.onSelected(choice);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={p.open} onClose={p.onClose}>
|
||||||
|
<DialogTitle>{p.title}</DialogTitle>
|
||||||
|
<DialogContent dividers>
|
||||||
|
<DialogContentText>{p.description}</DialogContentText>
|
||||||
|
|
||||||
|
<RadioGroup>
|
||||||
|
{accounts.list.list.map((option) => (
|
||||||
|
<FormControlLabel
|
||||||
|
value={option.id}
|
||||||
|
key={option.id}
|
||||||
|
control={
|
||||||
|
<Radio
|
||||||
|
disabled={
|
||||||
|
p.excludedAccounts?.find((a) => a.id === option.id) !==
|
||||||
|
undefined
|
||||||
|
}
|
||||||
|
checked={option.id === choice?.id}
|
||||||
|
onChange={() => setChoice(option)}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
label={
|
||||||
|
<ListItem>
|
||||||
|
<ListItemIcon>
|
||||||
|
<AccountWidget account={option} />
|
||||||
|
</ListItemIcon>
|
||||||
|
<ListItemText
|
||||||
|
primary={option.name}
|
||||||
|
secondary={<AmountWidget amount={option.balance} />}
|
||||||
|
/>
|
||||||
|
</ListItem>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={p.onClose}>Cancel</Button>
|
||||||
|
<Button onClick={submit} autoFocus disabled={choice === null}>
|
||||||
|
{p.confirmButton ?? "Submit"}
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Account } from "../../api/AccountApi";
|
||||||
|
import { SelectAccountDialog } from "../../dialogs/SelectAccountDialog";
|
||||||
|
|
||||||
|
type DialogContext = (
|
||||||
|
title: string,
|
||||||
|
description: string,
|
||||||
|
confirmButton?: string,
|
||||||
|
excludedAccounts?: Account[]
|
||||||
|
) => Promise<Account | undefined>;
|
||||||
|
|
||||||
|
const DialogContextK = React.createContext<DialogContext | null>(null);
|
||||||
|
|
||||||
|
export function ChooseAccountDialogProvider(
|
||||||
|
p: React.PropsWithChildren
|
||||||
|
): React.ReactElement {
|
||||||
|
const [title, setTitle] = React.useState("");
|
||||||
|
const [description, setDescription] = React.useState("");
|
||||||
|
const [confirmButton, setConfirmButton] = React.useState<
|
||||||
|
string | undefined
|
||||||
|
>();
|
||||||
|
const [excludedAccounts, setExcludedAccounts] = React.useState<
|
||||||
|
Account[] | undefined
|
||||||
|
>();
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
|
const cb = React.useRef<null | ((a: Account | undefined) => void)>(null);
|
||||||
|
|
||||||
|
const handleClose = (res?: Account) => {
|
||||||
|
setOpen(false);
|
||||||
|
|
||||||
|
if (cb.current !== null) cb.current(res);
|
||||||
|
cb.current = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const hook: DialogContext = (
|
||||||
|
title,
|
||||||
|
description,
|
||||||
|
confirmButton,
|
||||||
|
excludedAccounts
|
||||||
|
) => {
|
||||||
|
setTitle(title);
|
||||||
|
setDescription(description);
|
||||||
|
setConfirmButton(confirmButton);
|
||||||
|
setExcludedAccounts(excludedAccounts);
|
||||||
|
setOpen(true);
|
||||||
|
|
||||||
|
return new Promise((res) => {
|
||||||
|
cb.current = res;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DialogContextK.Provider value={hook}>
|
||||||
|
{p.children}
|
||||||
|
</DialogContextK.Provider>
|
||||||
|
|
||||||
|
{open && (
|
||||||
|
<SelectAccountDialog
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
onSelected={handleClose}
|
||||||
|
title={title}
|
||||||
|
description={description}
|
||||||
|
confirmButton={confirmButton}
|
||||||
|
excludedAccounts={excludedAccounts}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useSelectAccount(): DialogContext {
|
||||||
|
return React.useContext(DialogContextK)!;
|
||||||
|
}
|
@ -16,6 +16,7 @@ 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 { NotFoundRoute } from "./NotFound";
|
import { NotFoundRoute } from "./NotFound";
|
||||||
|
import { useSelectAccount } from "../hooks/context_providers/ChooseAccountDialogProvider";
|
||||||
|
|
||||||
export function AccountRoute(): React.ReactElement {
|
export function AccountRoute(): React.ReactElement {
|
||||||
const loadingMessage = useLoadingMessage();
|
const loadingMessage = useLoadingMessage();
|
||||||
@ -87,12 +88,23 @@ function MovementsTable(p: {
|
|||||||
movements: Movement[];
|
movements: Movement[];
|
||||||
needReload: (skipMovements: boolean) => void;
|
needReload: (skipMovements: boolean) => void;
|
||||||
}): React.ReactElement {
|
}): React.ReactElement {
|
||||||
|
const accounts = useAccounts();
|
||||||
const alert = useAlert();
|
const alert = useAlert();
|
||||||
const confirm = useConfirm();
|
const confirm = useConfirm();
|
||||||
|
|
||||||
|
const chooseAccount = useSelectAccount();
|
||||||
|
|
||||||
// Change account of movement
|
// Change account of movement
|
||||||
const handleMoveClick = async (movement: Movement) => {
|
const handleMoveClick = async (movement: Movement) => {
|
||||||
|
const target = await chooseAccount(
|
||||||
|
"Transfer movement",
|
||||||
|
`Please select the target account that will receive the movement: ${movement.label} (${movement.amount} €)`,
|
||||||
|
"Transfer movement",
|
||||||
|
[accounts.get(movement.account_id)!]
|
||||||
|
);
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
alert(target?.id?.toString() ?? "none");
|
||||||
};
|
};
|
||||||
|
|
||||||
// Delete movement
|
// Delete movement
|
||||||
|
@ -7,6 +7,7 @@ import { AccountsListProvider } from "../hooks/AccountsListProvider";
|
|||||||
import { AsyncWidget } from "./AsyncWidget";
|
import { AsyncWidget } from "./AsyncWidget";
|
||||||
import { MoneyNavList } from "./MoneyNavList";
|
import { MoneyNavList } from "./MoneyNavList";
|
||||||
import { MoneyWebAppBar } from "./MoneyWebAppBar";
|
import { MoneyWebAppBar } from "./MoneyWebAppBar";
|
||||||
|
import { ChooseAccountDialogProvider } from "../hooks/context_providers/ChooseAccountDialogProvider";
|
||||||
|
|
||||||
interface AuthInfoContext {
|
interface AuthInfoContext {
|
||||||
info: AuthInfo;
|
info: AuthInfo;
|
||||||
@ -48,6 +49,7 @@ export function BaseAuthenticatedPage(): React.ReactElement {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<AccountsListProvider>
|
<AccountsListProvider>
|
||||||
|
<ChooseAccountDialogProvider>
|
||||||
<Box
|
<Box
|
||||||
component="div"
|
component="div"
|
||||||
sx={{
|
sx={{
|
||||||
@ -86,6 +88,7 @@ export function BaseAuthenticatedPage(): React.ReactElement {
|
|||||||
</div>
|
</div>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
|
</ChooseAccountDialogProvider>
|
||||||
</AccountsListProvider>
|
</AccountsListProvider>
|
||||||
</AuthInfoContextK>
|
</AuthInfoContextK>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user