diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/popup/BalancePage.tsx')
-rw-r--r-- | packages/taler-wallet-webextension/src/popup/BalancePage.tsx | 152 |
1 files changed, 104 insertions, 48 deletions
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx index cdf507cb5..3275a0a07 100644 --- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx @@ -23,8 +23,10 @@ import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { MultiActionButton } from "../components/MultiActionButton.js"; import { useTranslationContext } from "../context/translation.js"; -import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; +import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; +import { ButtonHandler } from "../mui/handlers.js"; +import { compose, StateViewMap } from "../utils/index.js"; import { AddNewActionView } from "../wallet/AddNewActionView.js"; import * as wxApi from "../wxApi.js"; import { NoBalanceHelp } from "./NoBalanceHelp.js"; @@ -34,17 +36,46 @@ export interface Props { goToWalletHistory: (currency: string) => Promise<void>; goToWalletManualWithdraw: () => Promise<void>; } -export function BalancePage({ - goToWalletManualWithdraw, - goToWalletDeposit, - goToWalletHistory, -}: Props): VNode { - const { i18n } = useTranslationContext(); + +export type State = State.Loading | State.Error | State.Action | State.Balances; + +export namespace State { + export interface Loading { + status: "loading"; + error: undefined; + } + + export interface Error { + status: "error"; + error: HookError; + } + + export interface Action { + status: "action"; + error: undefined; + cancel: ButtonHandler; + } + + export interface Balances { + status: "balance"; + error: undefined; + balances: Balance[]; + addAction: ButtonHandler; + goToWalletDeposit: (currency: string) => Promise<void>; + goToWalletHistory: (currency: string) => Promise<void>; + goToWalletManualWithdraw: ButtonHandler; + } +} + +function useComponentState( + { goToWalletDeposit, goToWalletHistory, goToWalletManualWithdraw }: Props, + api: typeof wxApi, +): State { const [addingAction, setAddingAction] = useState(false); - const state = useAsyncAsHook(wxApi.getBalance); + const state = useAsyncAsHook(api.getBalance); useEffect(() => { - return wxApi.onUpdateNotification( + return api.onUpdateNotification( [NotificationType.WithdrawGroupFinished], () => { state?.retry(); @@ -52,58 +83,80 @@ export function BalancePage({ ); }); - const balances = !state || state.hasError ? [] : state.response.balances; - if (!state) { - return <Loading />; + return { + status: "loading", + error: undefined, + }; } - if (state.hasError) { - return ( - <LoadingError - title={<i18n.Translate>Could not load balance page</i18n.Translate>} - error={state} - /> - ); + return { + status: "error", + error: state, + }; } - if (addingAction) { - return <AddNewActionView onCancel={async () => setAddingAction(false)} />; + return { + status: "action", + error: undefined, + cancel: { + onClick: async () => setAddingAction(false), + }, + }; } + return { + status: "balance", + error: undefined, + balances: state.response.balances, + addAction: { + onClick: async () => setAddingAction(true), + }, + goToWalletManualWithdraw: { + onClick: goToWalletManualWithdraw, + }, + goToWalletDeposit, + goToWalletHistory, + }; +} + +const viewMapping: StateViewMap<State> = { + loading: Loading, + error: ErrorView, + action: ActionView, + balance: BalanceView, +}; +export const BalancePage = compose( + "BalancePage", + (p: Props) => useComponentState(p, wxApi), + viewMapping, +); + +function ErrorView({ error }: State.Error): VNode { + const { i18n } = useTranslationContext(); return ( - <BalanceView - balances={balances} - goToWalletManualWithdraw={goToWalletManualWithdraw} - goToWalletDeposit={goToWalletDeposit} - goToWalletHistory={goToWalletHistory} - goToAddAction={async () => setAddingAction(true)} + <LoadingError + title={<i18n.Translate>Could not load balance page</i18n.Translate>} + error={error} /> ); } -export interface BalanceViewProps { - balances: Balance[]; - goToWalletManualWithdraw: () => Promise<void>; - goToAddAction: () => Promise<void>; - goToWalletDeposit: (currency: string) => Promise<void>; - goToWalletHistory: (currency: string) => Promise<void>; + +function ActionView({ cancel }: State.Action): VNode { + return <AddNewActionView onCancel={cancel.onClick!} />; } -export function BalanceView({ - balances, - goToWalletManualWithdraw, - goToWalletDeposit, - goToWalletHistory, - goToAddAction, -}: BalanceViewProps): VNode { +export function BalanceView(state: State.Balances): VNode { const { i18n } = useTranslationContext(); - const currencyWithNonZeroAmount = balances + const currencyWithNonZeroAmount = state.balances .filter((b) => !Amounts.isZero(b.available)) .map((b) => b.available.split(":")[0]); - if (balances.length === 0) { + if (state.balances.length === 0) { return ( - <NoBalanceHelp goToWalletManualWithdraw={goToWalletManualWithdraw} /> + <NoBalanceHelp + goToWalletManualWithdraw={state.goToWalletManualWithdraw} + /> ); } @@ -111,23 +164,26 @@ export function BalanceView({ <Fragment> <section> <BalanceTable - balances={balances} - goToWalletHistory={goToWalletHistory} + balances={state.balances} + goToWalletHistory={state.goToWalletHistory} /> </section> <footer style={{ justifyContent: "space-between" }}> - <Button variant="contained" onClick={goToWalletManualWithdraw}> + <Button + variant="contained" + onClick={state.goToWalletManualWithdraw.onClick} + > <i18n.Translate>Withdraw</i18n.Translate> </Button> {currencyWithNonZeroAmount.length > 0 && ( <MultiActionButton label={(s) => <i18n.Translate>Deposit {s}</i18n.Translate>} actions={currencyWithNonZeroAmount} - onClick={(c) => goToWalletDeposit(c)} + onClick={(c) => state.goToWalletDeposit(c)} /> )} <JustInDevMode> - <Button onClick={goToAddAction}> + <Button onClick={state.addAction.onClick}> <i18n.Translate>Enter URI</i18n.Translate> </Button> </JustInDevMode> |