wallet-core/packages/taler-wallet-webextension/src/popup/BalancePage.tsx

188 lines
5.1 KiB
TypeScript
Raw Normal View History

2021-07-14 20:21:40 +02:00
/*
2022-06-06 17:05:26 +02:00
This file is part of GNU Taler
(C) 2022 Taler Systems S.A.
2021-07-14 20:21:40 +02:00
2022-06-06 17:05:26 +02:00
GNU Taler is free software; you can redistribute it and/or modify it under the
2021-07-14 20:21:40 +02:00
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
2022-06-06 17:05:26 +02:00
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
2021-07-14 20:21:40 +02:00
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
2022-06-06 17:05:26 +02:00
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
2021-07-14 20:21:40 +02:00
*/
import { Amounts, Balance, NotificationType } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact";
2022-04-26 03:37:41 +02:00
import { useEffect, useState } from "preact/hooks";
2022-03-29 04:41:07 +02:00
import { BalanceTable } from "../components/BalanceTable.js";
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 { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
2022-06-01 20:47:47 +02:00
import { Button } from "../mui/Button.js";
import { ButtonHandler } from "../mui/handlers.js";
import { compose, StateViewMap } from "../utils/index.js";
2022-03-29 04:41:07 +02:00
import { AddNewActionView } from "../wallet/AddNewActionView.js";
import * as wxApi from "../wxApi.js";
import { NoBalanceHelp } from "./NoBalanceHelp.js";
2022-03-17 19:00:34 +01:00
export interface Props {
2022-06-01 20:47:47 +02:00
goToWalletDeposit: (currency: string) => Promise<void>;
goToWalletHistory: (currency: string) => Promise<void>;
goToWalletManualWithdraw: () => Promise<void>;
2021-12-23 19:17:36 +01:00
}
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(api.getBalance);
2022-04-26 03:37:41 +02:00
useEffect(() => {
return api.onUpdateNotification(
2022-06-09 19:16:28 +02:00
[NotificationType.WithdrawGroupFinished],
() => {
state?.retry();
},
);
2022-04-26 03:37:41 +02:00
});
if (!state) {
return {
status: "loading",
error: undefined,
};
}
if (state.hasError) {
return {
status: "error",
error: state,
};
}
if (addingAction) {
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();
2021-11-15 15:18:58 +01:00
return (
<LoadingError
title={<i18n.Translate>Could not load balance page</i18n.Translate>}
error={error}
2021-11-15 15:18:58 +01:00
/>
);
2021-07-14 20:21:40 +02:00
}
function ActionView({ cancel }: State.Action): VNode {
return <AddNewActionView onCancel={cancel.onClick!} />;
2021-07-14 20:21:40 +02:00
}
export function BalanceView(state: State.Balances): VNode {
const { i18n } = useTranslationContext();
const currencyWithNonZeroAmount = state.balances
.filter((b) => !Amounts.isZero(b.available))
.map((b) => b.available.split(":")[0]);
2021-10-11 20:59:55 +02:00
if (state.balances.length === 0) {
return (
<NoBalanceHelp
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
/>
2021-11-15 15:18:58 +01:00
);
2021-10-11 20:59:55 +02:00
}
2021-11-15 15:18:58 +01:00
return (
<Fragment>
<section>
2021-12-23 19:17:36 +01:00
<BalanceTable
balances={state.balances}
goToWalletHistory={state.goToWalletHistory}
2021-12-23 19:17:36 +01:00
/>
</section>
2021-12-23 19:17:36 +01:00
<footer style={{ justifyContent: "space-between" }}>
<Button
variant="contained"
onClick={state.goToWalletManualWithdraw.onClick}
>
2022-08-14 15:10:37 +02:00
<i18n.Translate>Get</i18n.Translate>
2022-06-01 20:47:47 +02:00
</Button>
{currencyWithNonZeroAmount.length > 0 && (
<MultiActionButton
2022-08-14 15:10:37 +02:00
label={(s) => <i18n.Translate>Send {s}</i18n.Translate>}
actions={currencyWithNonZeroAmount}
onClick={(c) => state.goToWalletDeposit(c)}
/>
)}
2021-11-15 15:18:58 +01:00
</footer>
</Fragment>
2021-11-15 15:18:58 +01:00
);
2021-07-14 20:21:40 +02:00
}