some fixes
-fix fulfillment messages -fix product list pricing and image on payment -filter exchange by currency on withdrawal -error message on operation error on withdrawal -add taler url on balance page (just for dev) -add no balance help -better text when doing manual withdraw for the firt time -removed balance from wallet (just history) -removed pending page
This commit is contained in:
parent
2b2b8c1608
commit
606be7577b
@ -44,8 +44,6 @@ export enum Pages {
|
||||
backup_provider_detail = "/backup/provider/:pid",
|
||||
backup_provider_add = "/backup/provider/add",
|
||||
|
||||
pending = "/pending",
|
||||
|
||||
settings = "/settings",
|
||||
settings_exchange_add = "/settings/exchange/add",
|
||||
|
||||
|
@ -123,15 +123,20 @@ export const TicketWithAProductList = createExample(TestedComponent, {
|
||||
amount: "USD:10",
|
||||
products: [
|
||||
{
|
||||
description: "beer",
|
||||
description: "ten beers",
|
||||
price: "USD:1",
|
||||
quantity: 10,
|
||||
image: beer,
|
||||
},
|
||||
{
|
||||
description: "brown beer",
|
||||
price: "USD:2",
|
||||
description: "beer without image",
|
||||
price: "USD:1",
|
||||
quantity: 10,
|
||||
},
|
||||
{
|
||||
description: "one brown beer",
|
||||
price: "USD:2",
|
||||
quantity: 1,
|
||||
image: beer,
|
||||
},
|
||||
],
|
||||
|
@ -48,6 +48,7 @@ import { Part } from "../components/Part";
|
||||
import { QR } from "../components/QR";
|
||||
import {
|
||||
ButtonSuccess,
|
||||
LightText,
|
||||
LinkSuccess,
|
||||
SmallLightText,
|
||||
SuccessBox,
|
||||
@ -313,7 +314,9 @@ export function PaymentRequestView({
|
||||
<h3>Payment complete</h3>
|
||||
<p>
|
||||
{!payResult.contractTerms.fulfillment_message
|
||||
? "You will now be sent back to the merchant you came from."
|
||||
? payResult.contractTerms.fulfillment_url
|
||||
? `You are going to be redirected to ${payResult.contractTerms.fulfillment_url}`
|
||||
: "You can close this page."
|
||||
: payResult.contractTerms.fulfillment_message}
|
||||
</p>
|
||||
</SuccessBox>
|
||||
@ -373,19 +376,59 @@ function ProductList({ products }: { products: Product[] }): VNode {
|
||||
List of products
|
||||
</SmallLightText>
|
||||
<dl>
|
||||
{products.map((p, i) => (
|
||||
{products.map((p, i) => {
|
||||
if (p.price) {
|
||||
const pPrice = Amounts.parseOrThrow(p.price);
|
||||
return (
|
||||
<div key={i} style={{ display: "flex", textAlign: "left" }}>
|
||||
<div>
|
||||
<img
|
||||
src={p.image ? p.image : undefined}
|
||||
style={{ width: 32, height: 32 }}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<dt>
|
||||
{p.quantity ?? 1} x {p.description}{" "}
|
||||
<span style={{ color: "gray" }}>
|
||||
{Amounts.stringify(pPrice)}
|
||||
</span>
|
||||
</dt>
|
||||
<dd>
|
||||
<b>
|
||||
{Amounts.stringify(
|
||||
Amounts.mult(pPrice, p.quantity ?? 1).amount,
|
||||
)}
|
||||
</b>
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div key={i} style={{ display: "flex", textAlign: "left" }}>
|
||||
<div>
|
||||
<img src={p.image} style={{ width: 32, height: 32 }} />
|
||||
</div>
|
||||
<div>
|
||||
<dt>{p.description}</dt>
|
||||
<dt>
|
||||
{p.quantity ?? 1} x {p.description}
|
||||
</dt>
|
||||
<dd>
|
||||
{p.price} x {p.quantity} {p.unit ? `(${p.unit})` : ``}
|
||||
Total{` `}
|
||||
{p.price
|
||||
? `${Amounts.stringifyValue(
|
||||
Amounts.mult(
|
||||
Amounts.parseOrThrow(p.price),
|
||||
p.quantity ?? 1,
|
||||
).amount,
|
||||
)} ${p}`
|
||||
: "free"}
|
||||
</dd>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</dl>
|
||||
</Fragment>
|
||||
);
|
||||
|
@ -28,10 +28,12 @@ import {
|
||||
i18n,
|
||||
WithdrawUriInfoResponse,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { OperationFailedError } from "@gnu-taler/taler-wallet-core";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { Loading } from "../components/Loading";
|
||||
import { LoadingError } from "../components/LoadingError";
|
||||
import { ErrorTalerOperation } from "../components/ErrorTalerOperation";
|
||||
import { LogoHeader } from "../components/LogoHeader";
|
||||
import { Part } from "../components/Part";
|
||||
import { SelectList } from "../components/SelectList";
|
||||
@ -64,7 +66,6 @@ export interface ViewProps {
|
||||
onAccept: (b: boolean) => void;
|
||||
reviewing: boolean;
|
||||
reviewed: boolean;
|
||||
confirmed: boolean;
|
||||
terms: TermsState;
|
||||
knownExchanges: ExchangeListItem[];
|
||||
}
|
||||
@ -81,8 +82,12 @@ export function View({
|
||||
onReview,
|
||||
onAccept,
|
||||
reviewed,
|
||||
confirmed,
|
||||
}: ViewProps): VNode {
|
||||
const [withdrawError, setWithdrawError] = useState<
|
||||
OperationFailedError | undefined
|
||||
>(undefined);
|
||||
const [confirmDisabled, setConfirmDisabled] = useState<boolean>(false);
|
||||
|
||||
const needsReview = terms.status === "changed" || terms.status === "new";
|
||||
|
||||
const [switchingExchange, setSwitchingExchange] = useState(false);
|
||||
@ -90,15 +95,37 @@ export function View({
|
||||
undefined,
|
||||
);
|
||||
|
||||
const exchanges = knownExchanges.reduce(
|
||||
const exchanges = knownExchanges
|
||||
.filter((e) => e.currency === amount.currency)
|
||||
.reduce(
|
||||
(prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }),
|
||||
{},
|
||||
);
|
||||
|
||||
async function doWithdrawAndCheckError() {
|
||||
try {
|
||||
setConfirmDisabled(true);
|
||||
await onWithdraw();
|
||||
} catch (e) {
|
||||
if (e instanceof OperationFailedError) {
|
||||
setWithdrawError(e);
|
||||
}
|
||||
setConfirmDisabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<WalletAction>
|
||||
<LogoHeader />
|
||||
<h2>{i18n.str`Digital cash withdrawal`}</h2>
|
||||
|
||||
{withdrawError && (
|
||||
<ErrorTalerOperation
|
||||
title="Could not finish the withdrawal operation"
|
||||
error={withdrawError.operationError}
|
||||
/>
|
||||
)}
|
||||
|
||||
<section>
|
||||
<Part
|
||||
title="Total to withdraw"
|
||||
@ -168,8 +195,8 @@ export function View({
|
||||
{(terms.status === "accepted" || (needsReview && reviewed)) && (
|
||||
<ButtonSuccess
|
||||
upperCased
|
||||
disabled={!exchangeBaseUrl || confirmed}
|
||||
onClick={onWithdraw}
|
||||
disabled={!exchangeBaseUrl || confirmDisabled}
|
||||
onClick={doWithdrawAndCheckError}
|
||||
>
|
||||
{i18n.str`Confirm withdrawal`}
|
||||
</ButtonSuccess>
|
||||
@ -178,7 +205,7 @@ export function View({
|
||||
<ButtonWarning
|
||||
upperCased
|
||||
disabled={!exchangeBaseUrl}
|
||||
onClick={onWithdraw}
|
||||
onClick={doWithdrawAndCheckError}
|
||||
>
|
||||
{i18n.str`Withdraw anyway`}
|
||||
</ButtonWarning>
|
||||
@ -204,7 +231,6 @@ export function WithdrawPageWithParsedURI({
|
||||
|
||||
const [reviewing, setReviewing] = useState<boolean>(false);
|
||||
const [reviewed, setReviewed] = useState<boolean>(false);
|
||||
const [confirmed, setConfirmed] = useState<boolean>(false);
|
||||
|
||||
const knownExchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
|
||||
|
||||
@ -267,17 +293,12 @@ export function WithdrawPageWithParsedURI({
|
||||
|
||||
const onWithdraw = async (): Promise<void> => {
|
||||
if (!exchange) return;
|
||||
setConfirmed(true);
|
||||
console.log("accepting exchange", exchange);
|
||||
try {
|
||||
const res = await wxApi.acceptWithdrawal(uri, exchange);
|
||||
console.log("accept withdrawal response", res);
|
||||
if (res.confirmTransferUrl) {
|
||||
document.location.href = res.confirmTransferUrl;
|
||||
}
|
||||
} catch (e) {
|
||||
setConfirmed(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
@ -289,7 +310,6 @@ export function WithdrawPageWithParsedURI({
|
||||
terms={detailsHook.response.tos}
|
||||
onSwitchExchange={setCustomExchange}
|
||||
knownExchanges={knownExchanges}
|
||||
confirmed={confirmed}
|
||||
reviewed={reviewed}
|
||||
onAccept={onAccept}
|
||||
reviewing={reviewing}
|
||||
|
@ -14,8 +14,9 @@
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
|
||||
import { Amounts, Balance } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { BalanceTable } from "../components/BalanceTable";
|
||||
import { JustInDevMode } from "../components/JustInDevMode";
|
||||
import { Loading } from "../components/Loading";
|
||||
@ -23,8 +24,9 @@ import { LoadingError } from "../components/LoadingError";
|
||||
import { MultiActionButton } from "../components/MultiActionButton";
|
||||
import { ButtonBoxPrimary, ButtonPrimary } from "../components/styled";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { PageLink } from "../renderHtml";
|
||||
import { AddNewActionView } from "../wallet/AddNewActionView";
|
||||
import * as wxApi from "../wxApi";
|
||||
import { NoBalanceHelp } from "./NoBalanceHelp";
|
||||
|
||||
interface Props {
|
||||
goToWalletDeposit: (currency: string) => void;
|
||||
@ -36,6 +38,7 @@ export function BalancePage({
|
||||
goToWalletDeposit,
|
||||
goToWalletHistory,
|
||||
}: Props): VNode {
|
||||
const [addingAction, setAddingAction] = useState(false);
|
||||
const state = useAsyncAsHook(wxApi.getBalance);
|
||||
const balances = !state || state.hasError ? [] : state.response.balances;
|
||||
|
||||
@ -47,18 +50,24 @@ export function BalancePage({
|
||||
return <LoadingError title="Could not load balance page" error={state} />;
|
||||
}
|
||||
|
||||
if (addingAction) {
|
||||
return <AddNewActionView onCancel={() => setAddingAction(false)} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<BalanceView
|
||||
balances={balances}
|
||||
goToWalletManualWithdraw={goToWalletManualWithdraw}
|
||||
goToWalletDeposit={goToWalletDeposit}
|
||||
goToWalletHistory={goToWalletHistory}
|
||||
goToAddAction={() => setAddingAction(true)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
export interface BalanceViewProps {
|
||||
balances: Balance[];
|
||||
goToWalletManualWithdraw: () => void;
|
||||
goToAddAction: () => void;
|
||||
goToWalletDeposit: (currency: string) => void;
|
||||
goToWalletHistory: (currency: string) => void;
|
||||
}
|
||||
@ -68,6 +77,7 @@ export function BalanceView({
|
||||
goToWalletManualWithdraw,
|
||||
goToWalletDeposit,
|
||||
goToWalletHistory,
|
||||
goToAddAction,
|
||||
}: BalanceViewProps): VNode {
|
||||
const currencyWithNonZeroAmount = balances
|
||||
.filter((b) => !Amounts.isZero(b.available))
|
||||
@ -75,21 +85,7 @@ export function BalanceView({
|
||||
|
||||
if (balances.length === 0) {
|
||||
return (
|
||||
<Fragment>
|
||||
<p>
|
||||
<i18n.Translate>
|
||||
You have no balance to show.
|
||||
<a href="https://demo.taler.net/" style={{ display: "block" }}>
|
||||
Learn how to top up your wallet balance »
|
||||
</a>
|
||||
</i18n.Translate>
|
||||
</p>
|
||||
<footer style={{ justifyContent: "space-between" }}>
|
||||
<ButtonPrimary onClick={goToWalletManualWithdraw}>
|
||||
Withdraw
|
||||
</ButtonPrimary>
|
||||
</footer>
|
||||
</Fragment>
|
||||
<NoBalanceHelp goToWalletManualWithdraw={goToWalletManualWithdraw} />
|
||||
);
|
||||
}
|
||||
|
||||
@ -113,7 +109,7 @@ export function BalanceView({
|
||||
/>
|
||||
)}
|
||||
<JustInDevMode>
|
||||
<ButtonBoxPrimary onClick={() => null}>enter uri</ButtonBoxPrimary>
|
||||
<ButtonBoxPrimary onClick={goToAddAction}>enter uri</ButtonBoxPrimary>
|
||||
</JustInDevMode>
|
||||
</footer>
|
||||
</Fragment>
|
||||
|
@ -0,0 +1,27 @@
|
||||
import { i18n } from "@gnu-taler/taler-util";
|
||||
import { h, VNode } from "preact";
|
||||
import { ButtonBoxWarning, WarningBox } from "../components/styled";
|
||||
|
||||
export function NoBalanceHelp({
|
||||
goToWalletManualWithdraw,
|
||||
}: {
|
||||
goToWalletManualWithdraw: () => void;
|
||||
}): VNode {
|
||||
return (
|
||||
<WarningBox>
|
||||
<p>
|
||||
<b>
|
||||
<i18n.Translate>You have no balance to show.</i18n.Translate>
|
||||
</b>
|
||||
<br />
|
||||
<i18n.Translate>
|
||||
To withdraw money you can start from your bank site or click the
|
||||
"withdraw" button to use a known exchange.
|
||||
</i18n.Translate>
|
||||
</p>
|
||||
<ButtonBoxWarning onClick={() => goToWalletManualWithdraw()}>
|
||||
Withdraw
|
||||
</ButtonBoxWarning>
|
||||
</WarningBox>
|
||||
);
|
||||
}
|
@ -37,7 +37,6 @@ import { DeveloperPage } from "./popup/DeveloperPage";
|
||||
import { TalerActionFound } from "./popup/TalerActionFound";
|
||||
import { BackupPage } from "./wallet/BackupPage";
|
||||
import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
|
||||
import { Pending } from "./wallet/PendingPage";
|
||||
import { ProviderAddPage } from "./wallet/ProviderAddPage";
|
||||
import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
|
||||
|
||||
@ -126,8 +125,6 @@ function Application(): VNode {
|
||||
}}
|
||||
/>
|
||||
|
||||
<Route path={Pages.pending} component={Pending} />
|
||||
|
||||
<Route
|
||||
path={Pages.backup}
|
||||
component={BackupPage}
|
||||
|
@ -1,151 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
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
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createExample } from "../test-utils";
|
||||
import { BalanceView as TestedComponent } from "./BalancePage";
|
||||
|
||||
export default {
|
||||
title: "wallet/balance",
|
||||
component: TestedComponent,
|
||||
argTypes: {},
|
||||
};
|
||||
|
||||
export const EmptyBalance = createExample(TestedComponent, {
|
||||
balances: [],
|
||||
});
|
||||
|
||||
export const SomeCoins = createExample(TestedComponent, {
|
||||
balances: [
|
||||
{
|
||||
available: "USD:10.5",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
|
||||
balances: [
|
||||
{
|
||||
available: "EUR:1",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "TESTKUDOS:2000",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "JPY:4",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "EUR:15",
|
||||
pendingOutgoing: "EUR:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const NoCoinsInTreeCurrencies = createExample(TestedComponent, {
|
||||
balances: [
|
||||
{
|
||||
available: "EUR:3",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "USD:2",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "ARS:1",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "EUR:15",
|
||||
pendingOutgoing: "EUR:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
export const SomeCoinsInFiveCurrencies = createExample(TestedComponent, {
|
||||
balances: [
|
||||
{
|
||||
available: "USD:0",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "ARS:13451",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "EUR:202.02",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "EUR:0",
|
||||
pendingOutgoing: "EUR:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "JPY:0",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "EUR:0",
|
||||
pendingOutgoing: "EUR:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "JPY:51223233",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "EUR:0",
|
||||
pendingOutgoing: "EUR:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "DEMOKUDOS:6",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:0",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
{
|
||||
available: "TESTKUDOS:6",
|
||||
hasPendingTransactions: false,
|
||||
pendingIncoming: "USD:5",
|
||||
pendingOutgoing: "USD:0",
|
||||
requiresUserInput: false,
|
||||
},
|
||||
],
|
||||
});
|
@ -1,121 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
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
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { Amounts, Balance, i18n } from "@gnu-taler/taler-util";
|
||||
import { Fragment, h, VNode } from "preact";
|
||||
import { BalanceTable } from "../components/BalanceTable";
|
||||
import { Loading } from "../components/Loading";
|
||||
import { LoadingError } from "../components/LoadingError";
|
||||
import { MultiActionButton } from "../components/MultiActionButton";
|
||||
import { ButtonPrimary, Centered } from "../components/styled";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { PageLink } from "../renderHtml";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
interface Props {
|
||||
goToWalletDeposit: (currency: string) => void;
|
||||
goToWalletHistory: (currency: string) => void;
|
||||
goToWalletManualWithdraw: () => void;
|
||||
}
|
||||
|
||||
export function BalancePage({
|
||||
goToWalletManualWithdraw,
|
||||
goToWalletDeposit,
|
||||
goToWalletHistory,
|
||||
}: Props): VNode {
|
||||
const state = useAsyncAsHook(wxApi.getBalance);
|
||||
|
||||
const balances = !state || state.hasError ? [] : state.response.balances;
|
||||
|
||||
if (!state) {
|
||||
return <Loading />;
|
||||
}
|
||||
|
||||
if (state.hasError) {
|
||||
return <LoadingError title="Could not load balance page" error={state} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<BalanceView
|
||||
balances={balances}
|
||||
goToWalletManualWithdraw={goToWalletManualWithdraw}
|
||||
goToWalletDeposit={goToWalletDeposit}
|
||||
goToWalletHistory={goToWalletHistory}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export interface BalanceViewProps {
|
||||
balances: Balance[];
|
||||
goToWalletManualWithdraw: () => void;
|
||||
goToWalletDeposit: (currency: string) => void;
|
||||
goToWalletHistory: (currency: string) => void;
|
||||
}
|
||||
|
||||
export function BalanceView({
|
||||
balances,
|
||||
goToWalletManualWithdraw,
|
||||
goToWalletDeposit,
|
||||
goToWalletHistory,
|
||||
}: BalanceViewProps): VNode {
|
||||
const currencyWithNonZeroAmount = balances
|
||||
.filter((b) => !Amounts.isZero(b.available))
|
||||
.map((b) => b.available.split(":")[0]);
|
||||
|
||||
if (balances.length === 0) {
|
||||
return (
|
||||
<Fragment>
|
||||
<p>
|
||||
<Centered style={{ marginTop: 100 }}>
|
||||
<i18n.Translate>
|
||||
You have no balance to show. Need some{" "}
|
||||
<PageLink pageName="/welcome">help</PageLink> getting started?
|
||||
</i18n.Translate>
|
||||
</Centered>
|
||||
</p>
|
||||
<footer style={{ justifyContent: "space-between" }}>
|
||||
<div />
|
||||
<ButtonPrimary onClick={goToWalletManualWithdraw}>
|
||||
Withdraw
|
||||
</ButtonPrimary>
|
||||
</footer>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<section>
|
||||
<BalanceTable
|
||||
balances={balances}
|
||||
goToWalletHistory={goToWalletHistory}
|
||||
/>
|
||||
</section>
|
||||
<footer style={{ justifyContent: "space-between" }}>
|
||||
<ButtonPrimary onClick={goToWalletManualWithdraw}>
|
||||
Withdraw
|
||||
</ButtonPrimary>
|
||||
{currencyWithNonZeroAmount.length > 0 && (
|
||||
<MultiActionButton
|
||||
label={(s) => `Deposit ${s}`}
|
||||
actions={currencyWithNonZeroAmount}
|
||||
onClick={(c) => goToWalletDeposit(c)}
|
||||
/>
|
||||
)}
|
||||
</footer>
|
||||
</Fragment>
|
||||
);
|
||||
}
|
@ -98,12 +98,20 @@ export function CreateManualWithdraw({
|
||||
|
||||
if (!initialExchange) {
|
||||
return (
|
||||
<section>
|
||||
<h2>Manual Withdrawal</h2>
|
||||
<LightText>
|
||||
Choose a exchange from where the coins will be withdrawn. The exchange
|
||||
will send the coins to this wallet after receiving a wire transfer
|
||||
with the correct subject.
|
||||
</LightText>
|
||||
<Centered style={{ marginTop: 100 }}>
|
||||
<BoldLight>No exchange configured</BoldLight>
|
||||
<ButtonSuccess onClick={onAddExchange}>
|
||||
<i18n.Translate>Add exchange</i18n.Translate>
|
||||
</ButtonSuccess>
|
||||
</Centered>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,13 @@ import {
|
||||
import { Fragment, h } from "preact";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { ErrorMessage } from "../components/ErrorMessage";
|
||||
import { Button, ButtonPrimary, Input, WarningBox } from "../components/styled";
|
||||
import {
|
||||
Button,
|
||||
ButtonPrimary,
|
||||
Input,
|
||||
LightText,
|
||||
WarningBox,
|
||||
} from "../components/styled";
|
||||
|
||||
export interface Props {
|
||||
initialValue?: string;
|
||||
@ -89,6 +95,14 @@ export function ExchangeSetUrlPage({
|
||||
) : (
|
||||
<h2>Add exchange for {expectedCurrency}</h2>
|
||||
)}
|
||||
{!result && (
|
||||
<LightText>Enter the URL of an exchange you trust.</LightText>
|
||||
)}
|
||||
{result && (
|
||||
<LightText>
|
||||
An exchange has been found! Review the information and click next
|
||||
</LightText>
|
||||
)}
|
||||
{result && expectedCurrency && expectedCurrency !== result.currency && (
|
||||
<WarningBox>
|
||||
This exchange doesn't match the expected currency{" "}
|
||||
|
@ -35,7 +35,7 @@ import { HistoryView as TestedComponent } from "./History";
|
||||
import { createExample } from "../test-utils";
|
||||
|
||||
export default {
|
||||
title: "wallet/balance/history",
|
||||
title: "wallet/balance",
|
||||
component: TestedComponent,
|
||||
};
|
||||
|
||||
|
@ -37,6 +37,7 @@ import {
|
||||
import { Time } from "../components/Time";
|
||||
import { TransactionItem } from "../components/TransactionItem";
|
||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
|
||||
import { NoBalanceHelp } from "../popup/NoBalanceHelp";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
interface Props {
|
||||
@ -130,14 +131,7 @@ export function HistoryView({
|
||||
|
||||
if (balances.length === 0 || !selectedCurrency) {
|
||||
return (
|
||||
<WarningBox>
|
||||
<p>
|
||||
You have <b>no balance</b>. Withdraw some funds into your wallet
|
||||
</p>
|
||||
<ButtonBoxWarning onClick={() => goToWalletManualWithdraw()}>
|
||||
Withdraw
|
||||
</ButtonBoxWarning>
|
||||
</WarningBox>
|
||||
<NoBalanceHelp goToWalletManualWithdraw={goToWalletManualWithdraw} />
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
This file is part of GNU Taler
|
||||
(C) 2021 Taler Systems S.A.
|
||||
|
||||
GNU Taler is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
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
|
||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Sebastian Javier Marchano (sebasjm)
|
||||
*/
|
||||
|
||||
import { createExample } from "../test-utils";
|
||||
import { queryToSlashKeys } from "../utils/index";
|
||||
import { Pending as TestedComponent } from "./PendingPage";
|
||||
|
||||
export default {
|
||||
title: "wallet/pending",
|
||||
component: TestedComponent,
|
||||
};
|
||||
|
||||
export const InitialState = createExample(TestedComponent, {
|
||||
onVerify: queryToSlashKeys,
|
||||
});
|
@ -1,35 +0,0 @@
|
||||
/*
|
||||
This file is part of TALER
|
||||
(C) 2016 GNUnet e.V.
|
||||
|
||||
TALER is free software; you can redistribute it and/or modify it under the
|
||||
terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; either version 3, or (at your option) any later version.
|
||||
|
||||
TALER is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
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
|
||||
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
import { h, VNode } from "preact";
|
||||
import { useState } from "preact/hooks";
|
||||
import { ButtonPrimary } from "../components/styled";
|
||||
import { AddNewActionView } from "./AddNewActionView";
|
||||
|
||||
export function Pending(): VNode {
|
||||
const [addingAction, setAddingAction] = useState(false);
|
||||
|
||||
if (addingAction) {
|
||||
return <AddNewActionView onCancel={() => setAddingAction(false)} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<section>
|
||||
<div />
|
||||
<ButtonPrimary onClick={() => setAddingAction(true)}>+</ButtonPrimary>
|
||||
</section>
|
||||
);
|
||||
}
|
@ -20,7 +20,6 @@
|
||||
*/
|
||||
|
||||
import * as a1 from "./Backup.stories";
|
||||
import * as a2 from "./Balance.stories";
|
||||
import * as a3 from "./CreateManualWithdraw.stories";
|
||||
import * as a4 from "./DepositPage.stories";
|
||||
import * as a5 from "./ExchangeAddConfirm.stories";
|
||||
@ -35,20 +34,4 @@ import * as a13 from "./Transaction.stories";
|
||||
import * as a14 from "./Welcome.stories";
|
||||
import * as a15 from "./AddNewActionView.stories";
|
||||
|
||||
export default [
|
||||
a1,
|
||||
a2,
|
||||
a3,
|
||||
a4,
|
||||
a5,
|
||||
a6,
|
||||
a7,
|
||||
a8,
|
||||
a9,
|
||||
a10,
|
||||
a11,
|
||||
a12,
|
||||
a13,
|
||||
a14,
|
||||
a15,
|
||||
];
|
||||
export default [a1, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15];
|
||||
|
@ -47,7 +47,6 @@ import { DepositPage } from "./wallet/DepositPage";
|
||||
import { ExchangeAddPage } from "./wallet/ExchangeAddPage";
|
||||
import { HistoryPage } from "./wallet/History";
|
||||
import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage";
|
||||
import { Pending } from "./wallet/PendingPage";
|
||||
import { ProviderAddPage } from "./wallet/ProviderAddPage";
|
||||
import { ProviderDetailPage } from "./wallet/ProviderDetailPage";
|
||||
import { SettingsPage } from "./wallet/Settings";
|
||||
@ -85,6 +84,14 @@ function Application(): VNode {
|
||||
function clearNotification(): void {
|
||||
setGlobalNotification(undefined);
|
||||
}
|
||||
function clearNotificationWhenMovingOut(): void {
|
||||
// const movingOutFromNotification =
|
||||
// globalNotification && e.url !== globalNotification.to;
|
||||
if (globalNotification) {
|
||||
//&& movingOutFromNotification) {
|
||||
setGlobalNotification(undefined);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<DevContextProvider>
|
||||
@ -112,13 +119,7 @@ function Application(): VNode {
|
||||
)}
|
||||
<Router
|
||||
history={hash_history}
|
||||
onChange={() => {
|
||||
// const movingOutFromNotification =
|
||||
// globalNotification && e.url !== globalNotification.to;
|
||||
if (globalNotification) {
|
||||
setGlobalNotification(undefined);
|
||||
}
|
||||
}}
|
||||
onChange={clearNotificationWhenMovingOut}
|
||||
>
|
||||
<Route path={Pages.welcome} component={WelcomePage} />
|
||||
|
||||
@ -175,7 +176,6 @@ function Application(): VNode {
|
||||
{/**
|
||||
* PENDING
|
||||
*/}
|
||||
<Route path={Pages.pending} component={Pending} />
|
||||
<Route path={Pages.settings} component={SettingsPage} />
|
||||
|
||||
{/**
|
||||
|
Loading…
Reference in New Issue
Block a user