diff --git a/moneymgr_web/src/dialogs/SelectAccountDialog.tsx b/moneymgr_web/src/dialogs/SelectAccountDialog.tsx new file mode 100644 index 0000000..51a362d --- /dev/null +++ b/moneymgr_web/src/dialogs/SelectAccountDialog.tsx @@ -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(null); + console.log(choice); + const submit = () => { + if (choice) p.onSelected(choice); + }; + + return ( + + {p.title} + + {p.description} + + + {accounts.list.list.map((option) => ( + a.id === option.id) !== + undefined + } + checked={option.id === choice?.id} + onChange={() => setChoice(option)} + /> + } + label={ + + + + + } + /> + + } + /> + ))} + + + + + + + + ); +} diff --git a/moneymgr_web/src/hooks/context_providers/ChooseAccountDialogProvider.tsx b/moneymgr_web/src/hooks/context_providers/ChooseAccountDialogProvider.tsx new file mode 100644 index 0000000..c88ac52 --- /dev/null +++ b/moneymgr_web/src/hooks/context_providers/ChooseAccountDialogProvider.tsx @@ -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; + +const DialogContextK = React.createContext(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 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 ( + <> + + {p.children} + + + {open && ( + + )} + + ); +} + +export function useSelectAccount(): DialogContext { + return React.useContext(DialogContextK)!; +} diff --git a/moneymgr_web/src/routes/AccountRoute.tsx b/moneymgr_web/src/routes/AccountRoute.tsx index c62cb0e..d87b2ee 100644 --- a/moneymgr_web/src/routes/AccountRoute.tsx +++ b/moneymgr_web/src/routes/AccountRoute.tsx @@ -16,6 +16,7 @@ import { DateWidget } from "../widgets/DateWidget"; import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer"; import { NewMovementWidget } from "../widgets/NewMovementWidget"; import { NotFoundRoute } from "./NotFound"; +import { useSelectAccount } from "../hooks/context_providers/ChooseAccountDialogProvider"; export function AccountRoute(): React.ReactElement { const loadingMessage = useLoadingMessage(); @@ -87,12 +88,23 @@ function MovementsTable(p: { movements: Movement[]; needReload: (skipMovements: boolean) => void; }): React.ReactElement { + const accounts = useAccounts(); const alert = useAlert(); const confirm = useConfirm(); + const chooseAccount = useSelectAccount(); + // Change account of 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 + alert(target?.id?.toString() ?? "none"); }; // Delete movement diff --git a/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx b/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx index c03564c..8ffd231 100644 --- a/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx +++ b/moneymgr_web/src/widgets/BaseAuthenticatedPage.tsx @@ -7,6 +7,7 @@ import { AccountsListProvider } from "../hooks/AccountsListProvider"; import { AsyncWidget } from "./AsyncWidget"; import { MoneyNavList } from "./MoneyNavList"; import { MoneyWebAppBar } from "./MoneyWebAppBar"; +import { ChooseAccountDialogProvider } from "../hooks/context_providers/ChooseAccountDialogProvider"; interface AuthInfoContext { info: AuthInfo; @@ -48,44 +49,46 @@ export function BaseAuthenticatedPage(): React.ReactElement { }} > - - theme.palette.mode === "light" - ? theme.palette.grey[100] - : theme.palette.grey[900], - color: (theme) => - theme.palette.mode === "light" - ? theme.palette.grey[900] - : theme.palette.grey[100], - }} - > - - + + theme.palette.mode === "light" + ? theme.palette.grey[100] + : theme.palette.grey[900], + color: (theme) => + theme.palette.mode === "light" + ? theme.palette.grey[900] + : theme.palette.grey[100], }} > - -
+ + - -
+ +
+ +
+
- +
)}