Created select account input

This commit is contained in:
Pierre HUBERT 2025-05-12 21:40:48 +02:00
parent c54584550f
commit 3772dce01c
8 changed files with 86 additions and 14 deletions

View File

@ -35,6 +35,13 @@ export class AccountsList {
return this.list.find((a) => a.id === id) ?? null; return this.list.find((a) => a.id === id) ?? null;
} }
/**
* Get default account (if any) returning null if none found
*/
get default(): Account | null {
return this.list.find((a) => a.default_account) ?? null;
}
/** /**
* Update all accounts balances * Update all accounts balances
*/ */

View File

@ -15,7 +15,7 @@ import {
import React from "react"; import React from "react";
import { Account } from "../api/AccountApi"; import { Account } from "../api/AccountApi";
import { useAccounts } from "../hooks/AccountsListProvider"; import { useAccounts } from "../hooks/AccountsListProvider";
import { AccountWidget } from "../widgets/AccountWidget"; import { AccountIconWidget } from "../widgets/AccountIconWidget";
import { AmountWidget } from "../widgets/AmountWidget"; import { AmountWidget } from "../widgets/AmountWidget";
export function SelectAccountDialog(p: { export function SelectAccountDialog(p: {
@ -36,7 +36,12 @@ export function SelectAccountDialog(p: {
}; };
return ( return (
<Dialog open={p.open} onClose={() => { p.onClose(); }}> <Dialog
open={p.open}
onClose={() => {
p.onClose();
}}
>
<DialogTitle>{p.title}</DialogTitle> <DialogTitle>{p.title}</DialogTitle>
<DialogContent dividers> <DialogContent dividers>
<DialogContentText>{p.description}</DialogContentText> <DialogContentText>{p.description}</DialogContentText>
@ -53,13 +58,15 @@ export function SelectAccountDialog(p: {
undefined undefined
} }
checked={option.id === choice?.id} checked={option.id === choice?.id}
onChange={() => { setChoice(option); }} onChange={() => {
setChoice(option);
}}
/> />
} }
label={ label={
<ListItem> <ListItem>
<ListItemIcon> <ListItemIcon>
<AccountWidget account={option} /> <AccountIconWidget account={option} />
</ListItemIcon> </ListItemIcon>
<ListItemText <ListItemText
primary={option.name} primary={option.name}
@ -72,7 +79,13 @@ export function SelectAccountDialog(p: {
</RadioGroup> </RadioGroup>
</DialogContent> </DialogContent>
<DialogActions> <DialogActions>
<Button onClick={() => { p.onClose(); }}>Cancel</Button> <Button
onClick={() => {
p.onClose();
}}
>
Cancel
</Button>
<Button onClick={submit} autoFocus disabled={choice === null}> <Button onClick={submit} autoFocus disabled={choice === null}>
{p.confirmButton ?? "Submit"} {p.confirmButton ?? "Submit"}
</Button> </Button>

View File

@ -24,7 +24,7 @@ import { useSelectAccount } from "../hooks/context_providers/ChooseAccountDialog
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider"; import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider"; import { useLoadingMessage } from "../hooks/context_providers/LoadingMessageProvider";
import { useSnackbar } from "../hooks/context_providers/SnackbarProvider"; import { useSnackbar } from "../hooks/context_providers/SnackbarProvider";
import { AccountWidget } from "../widgets/AccountWidget"; import { AccountIconWidget } from "../widgets/AccountIconWidget";
import { AmountWidget } from "../widgets/AmountWidget"; import { AmountWidget } from "../widgets/AmountWidget";
import { AsyncWidget } from "../widgets/AsyncWidget"; import { AsyncWidget } from "../widgets/AsyncWidget";
import { DateWidget } from "../widgets/DateWidget"; import { DateWidget } from "../widgets/DateWidget";
@ -71,7 +71,7 @@ export function AccountRoute(): React.ReactElement {
<MoneyMgrWebRouteContainer <MoneyMgrWebRouteContainer
label={ label={
<span style={{ display: "inline-flex", alignItems: "center" }}> <span style={{ display: "inline-flex", alignItems: "center" }}>
<AccountWidget account={account} /> <AccountIconWidget account={account} />
&nbsp; &nbsp;
<span style={{ display: "inline-flex", flexDirection: "column" }}> <span style={{ display: "inline-flex", flexDirection: "column" }}>
<span>{account.name}</span> <span>{account.name}</span>

View File

@ -10,7 +10,7 @@ import { MoneyMgrWebRouteContainer } from "../widgets/MoneyMgrWebRouteContainer"
import { TimeWidget } from "../widgets/TimeWidget"; import { TimeWidget } from "../widgets/TimeWidget";
import DeleteIcon from "@mui/icons-material/DeleteOutlined"; import DeleteIcon from "@mui/icons-material/DeleteOutlined";
import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider"; import { useConfirm } from "../hooks/context_providers/ConfirmDialogProvider";
import { AccountWidget } from "../widgets/AccountWidget"; import { AccountIconWidget } from "../widgets/AccountIconWidget";
import { ServerApi } from "../api/ServerApi"; import { ServerApi } from "../api/ServerApi";
export function AccountsRoute(): React.ReactElement { export function AccountsRoute(): React.ReactElement {
@ -109,7 +109,7 @@ export function AccountsRoute(): React.ReactElement {
alignItems: "center", alignItems: "center",
}} }}
> >
<AccountWidget account={params.row} /> <AccountIconWidget account={params.row} />
{ {
ServerApi.Config.accounts_types.find( ServerApi.Config.accounts_types.find(
(t) => t.code === params.row.type (t) => t.code === params.row.type

View File

@ -3,7 +3,7 @@ import { ServerApi } from "../api/ServerApi";
import { useDarkTheme } from "../hooks/context_providers/DarkThemeProvider"; import { useDarkTheme } from "../hooks/context_providers/DarkThemeProvider";
import { toBase64 } from "@jsonjoy.com/base64"; import { toBase64 } from "@jsonjoy.com/base64";
export function AccountWidget(p: { account: Account }): React.ReactElement { export function AccountIconWidget(p: { account: Account }): React.ReactElement {
const darkTheme = useDarkTheme(); const darkTheme = useDarkTheme();
return ( return (

View File

@ -14,7 +14,7 @@ import React from "react";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { useAccounts } from "../hooks/AccountsListProvider"; import { useAccounts } from "../hooks/AccountsListProvider";
import { usePublicMode } from "../hooks/context_providers/PublicModeProvider"; import { usePublicMode } from "../hooks/context_providers/PublicModeProvider";
import { AccountWidget } from "./AccountWidget"; import { AccountIconWidget } from "./AccountIconWidget";
import { AmountWidget } from "./AmountWidget"; import { AmountWidget } from "./AmountWidget";
import { RouterLink } from "./RouterLink"; import { RouterLink } from "./RouterLink";
import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider"; import { useUnmatchedInboxEntriesCount } from "../hooks/UnmatchedInboxEntriesCountProvider";
@ -74,7 +74,7 @@ export function MoneyNavList(): React.ReactElement {
publicMode.enabled ? <></> : <AmountWidget amount={a.balance} /> publicMode.enabled ? <></> : <AmountWidget amount={a.balance} />
} }
uri={`/account/${a.id}`} uri={`/account/${a.id}`}
icon={<AccountWidget account={a} />} icon={<AccountIconWidget account={a} />}
/> />
))} ))}
</List> </List>

View File

@ -3,7 +3,7 @@ import CallReceivedIcon from "@mui/icons-material/CallReceived";
import React from "react"; import React from "react";
import { Movement, MovementApi } from "../api/MovementsApi"; import { Movement, MovementApi } from "../api/MovementsApi";
import { useAccounts } from "../hooks/AccountsListProvider"; import { useAccounts } from "../hooks/AccountsListProvider";
import { AccountWidget } from "./AccountWidget"; import { AccountIconWidget } from "./AccountIconWidget";
import { AmountWidget } from "./AmountWidget"; import { AmountWidget } from "./AmountWidget";
import { AsyncWidget } from "./AsyncWidget"; import { AsyncWidget } from "./AsyncWidget";
@ -53,7 +53,9 @@ export function MovementWidget(p: { id: number }): React.ReactElement {
<span style={{ width: "0.5em" }} /> <span style={{ width: "0.5em" }} />
&bull; &bull;
<span style={{ width: "0.5em" }} /> <span style={{ width: "0.5em" }} />
<AccountWidget account={accounts.get(movement!.account_id)!} /> <AccountIconWidget
account={accounts.get(movement!.account_id)!}
/>
{accounts.get(movement!.account_id)?.name} {accounts.get(movement!.account_id)?.name}
</span> </span>
</span> </span>

View File

@ -0,0 +1,50 @@
import { MenuItem, Select, Typography } from "@mui/material";
import { AccountIconWidget } from "../AccountIconWidget";
import { useAccounts } from "../../hooks/AccountsListProvider";
import { AmountWidget } from "../AmountWidget";
export function AccountInput(p: {
value: number;
onChange: (value: number) => void;
label?: string;
}): React.ReactElement {
const accounts = useAccounts();
let current = p.value;
if (!current && accounts.list.list.length > 0)
current = (accounts.list.default ?? accounts.list.list[0]).id;
return (
<Select
value={p.value}
label={p.label ?? ""}
onChange={(e) => p.onChange(Number(e.target.value))}
size="small"
>
{accounts.list.list.map((a) => (
<MenuItem value={a.id}>
<span
style={{
display: "inline-flex",
alignItems: "center",
height: "100%",
}}
>
<AccountIconWidget account={a} />
<span
style={{
marginLeft: "1em",
display: "flex",
flexDirection: "column",
}}
>
<span>{a.name}</span>
<Typography variant="caption">
<AmountWidget amount={a.balance} />
</Typography>
</span>
</span>
</MenuItem>
))}
</Select>
);
}