fix #7152
This commit is contained in:
parent
14f3d1e06d
commit
9b04d8bf35
@ -69,7 +69,7 @@
|
|||||||
"preact-cli": "^3.3.5",
|
"preact-cli": "^3.3.5",
|
||||||
"preact-render-to-string": "^5.1.19",
|
"preact-render-to-string": "^5.1.19",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"typescript": "^4.8.4"
|
"typescript": "4.9.4"
|
||||||
},
|
},
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"include": [
|
"include": [
|
||||||
|
@ -49,7 +49,7 @@ function RenderAmount(): VNode {
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
<AmountField
|
<AmountField
|
||||||
required
|
required
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
label={i18n.str`Amount`}
|
||||||
highestDenom={2000000}
|
highestDenom={2000000}
|
||||||
lowestDenom={0.01}
|
lowestDenom={0.01}
|
||||||
handler={handler}
|
handler={handler}
|
||||||
|
@ -21,6 +21,7 @@ import {
|
|||||||
amountMaxValue,
|
amountMaxValue,
|
||||||
Amounts,
|
Amounts,
|
||||||
Result,
|
Result,
|
||||||
|
TranslatedString,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -37,7 +38,7 @@ export function AmountField({
|
|||||||
highestDenom = 1,
|
highestDenom = 1,
|
||||||
required,
|
required,
|
||||||
}: {
|
}: {
|
||||||
label: VNode;
|
label: TranslatedString;
|
||||||
lowestDenom?: number;
|
lowestDenom?: number;
|
||||||
highestDenom?: number;
|
highestDenom?: number;
|
||||||
required?: boolean;
|
required?: boolean;
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
PaytoUri,
|
PaytoUri,
|
||||||
segwitMinAmount,
|
segwitMinAmount,
|
||||||
|
TranslatedString,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useRef, useState } from "preact/hooks";
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
@ -106,27 +107,18 @@ export function BankDetailsByPaytoType({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const accountPart = !payto.isKnown ? (
|
const accountPart = !payto.isKnown ? (
|
||||||
<Row
|
<Row name={i18n.str`Account`} value={payto.targetPath} />
|
||||||
name={<i18n.Translate>Account</i18n.Translate>}
|
|
||||||
value={payto.targetPath}
|
|
||||||
/>
|
|
||||||
) : payto.targetType === "x-taler-bank" ? (
|
) : payto.targetType === "x-taler-bank" ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<Row
|
<Row name={i18n.str`Bank host`} value={payto.host} />
|
||||||
name={<i18n.Translate>Bank host</i18n.Translate>}
|
<Row name={i18n.str`Bank account`} value={payto.account} />
|
||||||
value={payto.host}
|
|
||||||
/>
|
|
||||||
<Row
|
|
||||||
name={<i18n.Translate>Bank account</i18n.Translate>}
|
|
||||||
value={payto.account}
|
|
||||||
/>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : payto.targetType === "iban" ? (
|
) : payto.targetType === "iban" ? (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{payto.bic !== undefined ? (
|
{payto.bic !== undefined ? (
|
||||||
<Row name={<i18n.Translate>BIC</i18n.Translate>} value={payto.bic} />
|
<Row name={i18n.str`BIC`} value={payto.bic} />
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Row name={<i18n.Translate>IBAN</i18n.Translate>} value={payto.iban} />
|
<Row name={i18n.str`IBAN`} value={payto.iban} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
) : undefined;
|
) : undefined;
|
||||||
|
|
||||||
@ -146,19 +138,12 @@ export function BankDetailsByPaytoType({
|
|||||||
<table>
|
<table>
|
||||||
{accountPart}
|
{accountPart}
|
||||||
<Row
|
<Row
|
||||||
name={<i18n.Translate>Amount</i18n.Translate>}
|
name={i18n.str`Amount`}
|
||||||
value={<Amount value={amount} hideCurrency />}
|
value={<Amount value={amount} hideCurrency />}
|
||||||
/>
|
/>
|
||||||
<Row
|
<Row name={i18n.str`Subject`} value={subject} literal />
|
||||||
name={<i18n.Translate>Subject</i18n.Translate>}
|
|
||||||
value={subject}
|
|
||||||
literal
|
|
||||||
/>
|
|
||||||
{receiver ? (
|
{receiver ? (
|
||||||
<Row
|
<Row name={i18n.str`Receiver name`} value={receiver} />
|
||||||
name={<i18n.Translate>Receiver name</i18n.Translate>}
|
|
||||||
value={receiver}
|
|
||||||
/>
|
|
||||||
) : undefined}
|
) : undefined}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -200,7 +185,7 @@ function Row({
|
|||||||
value,
|
value,
|
||||||
literal,
|
literal,
|
||||||
}: {
|
}: {
|
||||||
name: VNode;
|
name: TranslatedString;
|
||||||
value: string | VNode;
|
value: string | VNode;
|
||||||
literal?: boolean;
|
literal?: boolean;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { ComponentChildren, Fragment, h, JSX, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, JSX, VNode } from "preact";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { Divider } from "../mui/Divider.js";
|
import { Divider } from "../mui/Divider.js";
|
||||||
@ -20,7 +21,7 @@ import { Grid } from "../mui/Grid.js";
|
|||||||
import { Paper } from "../mui/Paper.js";
|
import { Paper } from "../mui/Paper.js";
|
||||||
|
|
||||||
interface Props extends JSX.HTMLAttributes<HTMLDivElement> {
|
interface Props extends JSX.HTMLAttributes<HTMLDivElement> {
|
||||||
titleHead?: VNode;
|
titleHead?: VNode | TranslatedString;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
// elements: {
|
// elements: {
|
||||||
// icon?: VNode;
|
// icon?: VNode;
|
||||||
|
@ -14,14 +14,15 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
onToggle?: () => Promise<void>;
|
onToggle?: () => Promise<void>;
|
||||||
label: VNode;
|
label: TranslatedString;
|
||||||
name: string;
|
name: string;
|
||||||
description?: VNode;
|
description?: VNode | TranslatedString;
|
||||||
}
|
}
|
||||||
export function Checkbox({
|
export function Checkbox({
|
||||||
name,
|
name,
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import { useTranslationContext } from "../../../web-util/src/index.browser.js";
|
||||||
|
import {
|
||||||
|
ErrorAlert,
|
||||||
|
Alert as AlertNotification,
|
||||||
|
useAlertContext,
|
||||||
|
} from "../context/alert.js";
|
||||||
|
import { Alert } from "../mui/Alert.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author sebasjm
|
||||||
|
*/
|
||||||
|
|
||||||
|
function AlertContext({
|
||||||
|
context,
|
||||||
|
cause,
|
||||||
|
}: {
|
||||||
|
cause: unknown;
|
||||||
|
context: undefined | object;
|
||||||
|
}): VNode {
|
||||||
|
const [more, setMore] = useState(false);
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
if (!more) {
|
||||||
|
return (
|
||||||
|
<div style={{ display: "flex", justifyContent: "right" }}>
|
||||||
|
<a onClick={() => setMore(true)}>
|
||||||
|
<i18n.Translate>more info</i18n.Translate>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<pre style={{ overflow: "overlay" }}>
|
||||||
|
{JSON.stringify(
|
||||||
|
context === undefined ? { cause } : { context, cause },
|
||||||
|
undefined,
|
||||||
|
2,
|
||||||
|
)}
|
||||||
|
</pre>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ErrorAlertView({
|
||||||
|
error: alert,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
error: ErrorAlert;
|
||||||
|
onClose?: () => Promise<void>;
|
||||||
|
}): VNode {
|
||||||
|
return (
|
||||||
|
<Alert title={alert.message} severity={alert.type} onClose={onClose}>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<div>{alert.description}</div>
|
||||||
|
<AlertContext context={alert.context} cause={alert.cause} />
|
||||||
|
</div>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AlertView({
|
||||||
|
alert,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
alert: AlertNotification;
|
||||||
|
onClose?: () => Promise<void>;
|
||||||
|
}): VNode {
|
||||||
|
return (
|
||||||
|
<Alert title={alert.message} severity={alert.type} onClose={onClose}>
|
||||||
|
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||||
|
<div>{alert.description}</div>
|
||||||
|
</div>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CurrentAlerts(): VNode {
|
||||||
|
const { alerts, removeAlert } = useAlertContext();
|
||||||
|
if (alerts.length === 0) return <Fragment />;
|
||||||
|
return (
|
||||||
|
<Wrapper>
|
||||||
|
{alerts.map((n, i) => (
|
||||||
|
<AlertView key={i} alert={n} onClose={async () => removeAlert(n)} />
|
||||||
|
))}
|
||||||
|
</Wrapper>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Wrapper({ children }: { children: ComponentChildren }): VNode {
|
||||||
|
return <div style={{ margin: "2em" }}>{children}</div>;
|
||||||
|
}
|
@ -13,6 +13,7 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.svg";
|
||||||
@ -22,7 +23,7 @@ export function ErrorMessage({
|
|||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
}: {
|
}: {
|
||||||
title: VNode;
|
title: TranslatedString;
|
||||||
description?: string | VNode;
|
description?: string | VNode;
|
||||||
}): VNode | null {
|
}): VNode | null {
|
||||||
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
const [showErrorDetail, setShowErrorDetail] = useState(false);
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
import { TalerErrorDetail, TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import arrowDown from "../svg/chevron-down.svg";
|
import arrowDown from "../svg/chevron-down.svg";
|
||||||
@ -24,7 +24,7 @@ export function ErrorTalerOperation({
|
|||||||
title,
|
title,
|
||||||
error,
|
error,
|
||||||
}: {
|
}: {
|
||||||
title?: VNode;
|
title?: TranslatedString;
|
||||||
error?: TalerErrorDetail;
|
error?: TalerErrorDetail;
|
||||||
}): VNode | null {
|
}): VNode | null {
|
||||||
const { devMode } = useDevContext();
|
const { devMode } = useDevContext();
|
||||||
|
@ -13,30 +13,88 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
import { css } from "@linaria/core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
|
import ProgressIcon from "../svg/progress.svg";
|
||||||
import { CenteredText } from "./styled/index.js";
|
import { CenteredText } from "./styled/index.js";
|
||||||
|
|
||||||
|
const fadeIn = css`
|
||||||
|
& {
|
||||||
|
animation: fadein 3s;
|
||||||
|
}
|
||||||
|
@keyframes fadein {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export function Loading(): VNode {
|
export function Loading(): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const [tooLong, setTooLong] = useState(false);
|
return (
|
||||||
useEffect(() => {
|
<section style={{ margin: "auto" }}>
|
||||||
const id = setTimeout(() => {
|
<CenteredText class={fadeIn}>
|
||||||
setTooLong(true);
|
<i18n.Translate>Loading</i18n.Translate>...
|
||||||
}, 500);
|
</CenteredText>
|
||||||
return () => {
|
{/* <div class={ripple} style={{ "--size": "250px" }}>
|
||||||
clearTimeout(id);
|
<div></div>
|
||||||
};
|
<div></div>
|
||||||
});
|
</div> */}
|
||||||
if (tooLong) {
|
<div class={fadeIn} dangerouslySetInnerHTML={{ __html: ProgressIcon }} />
|
||||||
return (
|
</section>
|
||||||
<section style={{ margin: "auto" }}>
|
);
|
||||||
<CenteredText>
|
|
||||||
<i18n.Translate>Loading</i18n.Translate>...
|
|
||||||
</CenteredText>
|
|
||||||
</section>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return <Fragment />;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ripple = css`
|
||||||
|
& {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
}
|
||||||
|
& div {
|
||||||
|
position: absolute;
|
||||||
|
border: 4px solid black;
|
||||||
|
opacity: 1;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||||
|
}
|
||||||
|
& div:nth-child(2) {
|
||||||
|
animation-delay: -0.3s;
|
||||||
|
}
|
||||||
|
@keyframes lds-ripple {
|
||||||
|
0% {
|
||||||
|
top: calc(var(--size) / 2);
|
||||||
|
left: calc(var(--size) / 2);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
14.9% {
|
||||||
|
top: calc(var(--size) / 2);
|
||||||
|
left: calc(var(--size) / 2);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
15% {
|
||||||
|
top: calc(var(--size) / 2);
|
||||||
|
left: calc(var(--size) / 2);
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: var(--size);
|
||||||
|
height: var(--size);
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is part of GNU Taler
|
|
||||||
(C) 2022 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/>
|
|
||||||
*/
|
|
||||||
import { h, VNode } from "preact";
|
|
||||||
import { HookError } from "../hooks/useAsyncAsHook.js";
|
|
||||||
import { ErrorMessage } from "./ErrorMessage.js";
|
|
||||||
import { ErrorTalerOperation } from "./ErrorTalerOperation.js";
|
|
||||||
|
|
||||||
export interface Props {
|
|
||||||
title: VNode;
|
|
||||||
error: HookError;
|
|
||||||
}
|
|
||||||
export function LoadingError({ title, error }: Props): VNode {
|
|
||||||
if (error.operational) {
|
|
||||||
return <ErrorTalerOperation title={title} error={error.details} />;
|
|
||||||
}
|
|
||||||
return <ErrorMessage title={title} description={error.message} />;
|
|
||||||
}
|
|
@ -13,7 +13,7 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
import { getUnpackedSettings } from "http2";
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
@ -21,7 +21,7 @@ import arrowDown from "../svg/chevron-down.svg";
|
|||||||
import { ParagraphClickable } from "./styled/index.js";
|
import { ParagraphClickable } from "./styled/index.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
label: (s: string) => VNode;
|
label: (s: string) => TranslatedString;
|
||||||
actions: string[];
|
actions: string[];
|
||||||
onClick: (s: string) => Promise<void>;
|
onClick: (s: string) => Promise<void>;
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,11 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { PaytoUri, stringifyPaytoUri } from "@gnu-taler/taler-util";
|
import {
|
||||||
|
PaytoUri,
|
||||||
|
stringifyPaytoUri,
|
||||||
|
TranslatedString,
|
||||||
|
} from "@gnu-taler/taler-util";
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -27,8 +31,8 @@ import {
|
|||||||
|
|
||||||
export type Kind = "positive" | "negative" | "neutral";
|
export type Kind = "positive" | "negative" | "neutral";
|
||||||
interface Props {
|
interface Props {
|
||||||
title: VNode | string;
|
title: VNode | TranslatedString;
|
||||||
text: VNode | string;
|
text: VNode | TranslatedString;
|
||||||
kind?: Kind;
|
kind?: Kind;
|
||||||
big?: boolean;
|
big?: boolean;
|
||||||
showSign?: boolean;
|
showSign?: boolean;
|
||||||
|
@ -19,6 +19,7 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
|
TranslatedString,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
@ -109,8 +110,10 @@ export function PaymentButtons({
|
|||||||
<section>
|
<section>
|
||||||
{payStatus.paid && payStatus.contractTerms.fulfillment_message && (
|
{payStatus.paid && payStatus.contractTerms.fulfillment_message && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant message</i18n.Translate>}
|
title={i18n.str`Merchant message`}
|
||||||
text={payStatus.contractTerms.fulfillment_message}
|
text={
|
||||||
|
payStatus.contractTerms.fulfillment_message as TranslatedString
|
||||||
|
}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -131,11 +134,7 @@ function PayWithMobile({ uri }: { uri: string }): VNode {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
||||||
{!showQR ? (
|
{!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
|
||||||
<i18n.Translate>Pay with a mobile phone</i18n.Translate>
|
|
||||||
) : (
|
|
||||||
<i18n.Translate>Hide QR</i18n.Translate>
|
|
||||||
)}
|
|
||||||
</LinkSuccess>
|
</LinkSuccess>
|
||||||
{showQR && (
|
{showQR && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -87,7 +87,7 @@ export function PendingTransactionsView({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Banner
|
<Banner
|
||||||
titleHead={<i18n.Translate>PENDING OPERATIONS</i18n.Translate>}
|
titleHead={i18n.str`PENDING OPERATIONS`}
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: "lightcyan",
|
backgroundColor: "lightcyan",
|
||||||
maxHeight: 150,
|
maxHeight: 150,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { NiceSelect } from "./styled/index.js";
|
import { NiceSelect } from "./styled/index.js";
|
||||||
@ -21,7 +22,7 @@ import { NiceSelect } from "./styled/index.js";
|
|||||||
interface Props {
|
interface Props {
|
||||||
value?: string;
|
value?: string;
|
||||||
onChange?: (s: string) => void;
|
onChange?: (s: string) => void;
|
||||||
label: VNode;
|
label: VNode | TranslatedString;
|
||||||
list: {
|
list: {
|
||||||
[label: string]: string;
|
[label: string]: string;
|
||||||
};
|
};
|
||||||
|
@ -94,7 +94,10 @@ export const Error = createExample(ErrorView, {
|
|||||||
error: {
|
error: {
|
||||||
hasError: true,
|
hasError: true,
|
||||||
message: "message",
|
message: "message",
|
||||||
operational: false,
|
// details: {
|
||||||
|
// co
|
||||||
|
// },
|
||||||
|
type: "error",
|
||||||
// details: {
|
// details: {
|
||||||
// code: 123,
|
// code: 123,
|
||||||
// },
|
// },
|
||||||
|
@ -22,15 +22,16 @@ import { styled } from "@linaria/react";
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { Modal } from "../components/Modal.js";
|
import { Modal } from "../components/Modal.js";
|
||||||
import { Time } from "../components/Time.js";
|
import { Time } from "../components/Time.js";
|
||||||
|
import { alertFromError } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../mui/handlers.js";
|
import { ButtonHandler } from "../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../utils/index.js";
|
import { compose, StateViewMap } from "../utils/index.js";
|
||||||
import { Amount } from "./Amount.js";
|
import { Amount } from "./Amount.js";
|
||||||
|
import { AlertView } from "./CurrentAlerts.js";
|
||||||
import { Link } from "./styled/index.js";
|
import { Link } from "./styled/index.js";
|
||||||
|
|
||||||
const ContractTermsTable = styled.table`
|
const ContractTermsTable = styled.table`
|
||||||
@ -160,13 +161,12 @@ export function ErrorView({
|
|||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
<Modal title="Full detail" onClose={hideHandler}>
|
<Modal title="Full detail" onClose={hideHandler}>
|
||||||
<LoadingError
|
<AlertView
|
||||||
title={
|
alert={alertFromError(
|
||||||
<i18n.Translate>
|
i18n.str`Could not load purchase proposal details`,
|
||||||
Could not load purchase proposal details
|
error,
|
||||||
</i18n.Translate>
|
{ proposalId },
|
||||||
}
|
)}
|
||||||
error={error}
|
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -15,14 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ToggleHandler } from "../../mui/handlers.js";
|
import { ToggleHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
|
import { ErrorAlertView } from "../CurrentAlerts.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { TermsState } from "./utils.js";
|
import { TermsState } from "./utils.js";
|
||||||
import {
|
import {
|
||||||
ErrorAcceptingView,
|
|
||||||
LoadingUriView,
|
|
||||||
ShowButtonsAcceptedTosView,
|
ShowButtonsAcceptedTosView,
|
||||||
ShowButtonsNonAcceptedTosView,
|
ShowButtonsNonAcceptedTosView,
|
||||||
ShowTosContentView,
|
ShowTosContentView,
|
||||||
@ -35,8 +34,7 @@ export interface Props {
|
|||||||
|
|
||||||
export type State =
|
export type State =
|
||||||
| State.Loading
|
| State.Loading
|
||||||
| State.LoadingUriError
|
| State.Error
|
||||||
| State.ErrorAccepting
|
|
||||||
| State.ShowButtonsAccepted
|
| State.ShowButtonsAccepted
|
||||||
| State.ShowButtonsNotAccepted
|
| State.ShowButtonsNotAccepted
|
||||||
| State.ShowContent;
|
| State.ShowContent;
|
||||||
@ -47,14 +45,9 @@ export namespace State {
|
|||||||
error: undefined;
|
error: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface Error {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
|
||||||
|
|
||||||
export interface ErrorAccepting {
|
|
||||||
status: "error-accepting";
|
|
||||||
error: HookError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -79,11 +72,10 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"show-content": ShowTosContentView,
|
"show-content": ShowTosContentView,
|
||||||
"show-buttons-accepted": ShowButtonsAcceptedTosView,
|
"show-buttons-accepted": ShowButtonsAcceptedTosView,
|
||||||
"show-buttons-not-accepted": ShowButtonsNonAcceptedTosView,
|
"show-buttons-not-accepted": ShowButtonsNonAcceptedTosView,
|
||||||
"error-accepting": ErrorAcceptingView,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const TermsOfService = compose(
|
export const TermsOfService = compose(
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError, useAlertContext } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
import { buildTermsOfServiceState } from "./utils.js";
|
import { buildTermsOfServiceState } from "./utils.js";
|
||||||
@ -25,9 +27,8 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State {
|
|||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
const readOnly = !onChange;
|
const readOnly = !onChange;
|
||||||
const [showContent, setShowContent] = useState<boolean>(readOnly);
|
const [showContent, setShowContent] = useState<boolean>(readOnly);
|
||||||
const [errorAccepting, setErrorAccepting] = useState<Error | undefined>(
|
const { i18n } = useTranslationContext();
|
||||||
undefined,
|
const { pushAlert } = useAlertContext();
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For the exchange selected, bring the status of the terms of service
|
* For the exchange selected, bring the status of the terms of service
|
||||||
@ -54,22 +55,13 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State {
|
|||||||
}
|
}
|
||||||
if (terms.hasError) {
|
if (terms.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-error",
|
status: "error",
|
||||||
error: terms,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
terms,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (errorAccepting) {
|
|
||||||
return {
|
|
||||||
status: "error-accepting",
|
|
||||||
error: {
|
|
||||||
hasError: true,
|
|
||||||
operational: false,
|
|
||||||
message: errorAccepting.message,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
const { state } = terms.response;
|
const { state } = terms.response;
|
||||||
|
|
||||||
async function onUpdate(accepted: boolean): Promise<void> {
|
async function onUpdate(accepted: boolean): Promise<void> {
|
||||||
@ -77,13 +69,13 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (accepted) {
|
if (accepted) {
|
||||||
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||||
exchangeBaseUrl: exchangeUrl,
|
exchangeBaseUrl: exchangeUrl,
|
||||||
etag: state.version,
|
etag: state.version,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// mark as not accepted
|
// mark as not accepted
|
||||||
api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
await api.wallet.call(WalletApiOperation.SetExchangeTosAccepted, {
|
||||||
exchangeBaseUrl: exchangeUrl,
|
exchangeBaseUrl: exchangeUrl,
|
||||||
etag: undefined,
|
etag: undefined,
|
||||||
});
|
});
|
||||||
@ -91,11 +83,7 @@ export function useComponentState({ exchangeUrl, onChange }: Props): State {
|
|||||||
// setAccepted(accepted);
|
// setAccepted(accepted);
|
||||||
if (!readOnly) onChange(accepted); //external update
|
if (!readOnly) onChange(accepted); //external update
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
pushAlert(alertFromError(i18n.str`Could not accept terms of service`, e));
|
||||||
//FIXME: uncomment this and display error
|
|
||||||
// setErrorAccepting(e.message);
|
|
||||||
setErrorAccepting(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,49 +14,23 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ExchangeTosStatus } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
|
||||||
import { TermsDocument, TermsState } from "./utils.js";
|
|
||||||
import { State } from "./index.js";
|
|
||||||
import { CheckboxOutlined } from "../../components/CheckboxOutlined.js";
|
import { CheckboxOutlined } from "../../components/CheckboxOutlined.js";
|
||||||
|
import { ExchangeXmlTos } from "../../components/ExchangeToS.js";
|
||||||
import {
|
import {
|
||||||
LinkSuccess,
|
LinkSuccess,
|
||||||
TermsOfService,
|
TermsOfService,
|
||||||
WarningBox,
|
WarningBox,
|
||||||
WarningText,
|
WarningText,
|
||||||
} from "../../components/styled/index.js";
|
} from "../../components/styled/index.js";
|
||||||
import { ExchangeXmlTos } from "../../components/ExchangeToS.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { ToggleHandler } from "../../mui/handlers.js";
|
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { ExchangeTosStatus } from "@gnu-taler/taler-util";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ErrorAcceptingView({ error }: State.ErrorAccepting): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ShowButtonsAcceptedTosView({
|
export function ShowButtonsAcceptedTosView({
|
||||||
termsAccepted,
|
termsAccepted,
|
||||||
showingTermsOfService,
|
showingTermsOfService,
|
||||||
terms,
|
|
||||||
}: State.ShowButtonsAccepted): VNode {
|
}: State.ShowButtonsAccepted): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const ableToReviewTermsOfService =
|
const ableToReviewTermsOfService =
|
||||||
|
@ -535,7 +535,7 @@ export const LinkDestructive = styled(Link)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const LinkPrimary = styled(Link)`
|
export const LinkPrimary = styled(Link)`
|
||||||
color: rgb(66, 184, 221);
|
color: black;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
|
export const ButtonPrimary = styled(ButtonVariant)<{ small?: boolean }>`
|
||||||
|
118
packages/taler-wallet-webextension/src/context/alert.ts
Normal file
118
packages/taler-wallet-webextension/src/context/alert.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2022 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 { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
|
import { ComponentChildren, createContext, h, VNode } from "preact";
|
||||||
|
import { useContext, useState } from "preact/hooks";
|
||||||
|
|
||||||
|
export type AlertType = "info" | "warning" | "error" | "success";
|
||||||
|
|
||||||
|
export interface Alert {
|
||||||
|
message: TranslatedString;
|
||||||
|
description: TranslatedString | VNode;
|
||||||
|
type: AlertType;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ErrorAlert extends Alert {
|
||||||
|
type: "error";
|
||||||
|
context: object;
|
||||||
|
cause: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Type = {
|
||||||
|
alerts: Alert[];
|
||||||
|
pushAlert: (n: Alert) => void;
|
||||||
|
removeAlert: (n: Alert) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initial: Type = {
|
||||||
|
alerts: [],
|
||||||
|
pushAlert: () => {
|
||||||
|
null;
|
||||||
|
},
|
||||||
|
removeAlert: () => {
|
||||||
|
null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Context = createContext<Type>(initial);
|
||||||
|
|
||||||
|
type AlertWithDate = Alert & { since: Date };
|
||||||
|
|
||||||
|
type Props = Partial<Type> & {
|
||||||
|
children: ComponentChildren;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AlertProvider = ({ children }: Props): VNode => {
|
||||||
|
const timeout = 3000;
|
||||||
|
|
||||||
|
const [alerts, setAlerts] = useState<AlertWithDate[]>([]);
|
||||||
|
|
||||||
|
const pushAlert = (n: Alert): void => {
|
||||||
|
const entry = { ...n, since: new Date() };
|
||||||
|
setAlerts((ns) => [...ns, entry]);
|
||||||
|
if (n.type !== "error") {
|
||||||
|
setTimeout(() => {
|
||||||
|
setAlerts((ns) => ns.filter((x) => x.since !== entry.since));
|
||||||
|
}, timeout);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeAlert = (alert: Alert): void => {
|
||||||
|
setAlerts((ns: AlertWithDate[]) => ns.filter((n) => n !== alert));
|
||||||
|
};
|
||||||
|
|
||||||
|
return h(Context.Provider, {
|
||||||
|
value: { alerts, pushAlert, removeAlert },
|
||||||
|
children,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAlertContext = (): Type => useContext(Context);
|
||||||
|
|
||||||
|
export function alertFromError(
|
||||||
|
message: TranslatedString,
|
||||||
|
error: unknown,
|
||||||
|
...context: any[]
|
||||||
|
): ErrorAlert {
|
||||||
|
let description = "" as TranslatedString;
|
||||||
|
|
||||||
|
const isObject = typeof error === "object" &&
|
||||||
|
error !== null;
|
||||||
|
const hasMessage =
|
||||||
|
isObject &&
|
||||||
|
"message" in error &&
|
||||||
|
typeof error.message === "string";
|
||||||
|
|
||||||
|
if (hasMessage) {
|
||||||
|
description = error.message as TranslatedString;
|
||||||
|
} else {
|
||||||
|
description = `Unknown error: ${String(error)}` as TranslatedString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "error",
|
||||||
|
message,
|
||||||
|
description,
|
||||||
|
cause: error,
|
||||||
|
context,
|
||||||
|
};
|
||||||
|
}
|
@ -15,12 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson, AmountString } from "@gnu-taler/taler-util";
|
import { AmountJson, AmountString } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerDepositUri: string | undefined;
|
talerDepositUri: string | undefined;
|
||||||
@ -37,8 +38,8 @@ export namespace State {
|
|||||||
error: undefined;
|
error: undefined;
|
||||||
}
|
}
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
export interface Ready {
|
export interface Ready {
|
||||||
status: "ready";
|
status: "ready";
|
||||||
@ -57,7 +58,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -38,12 +40,16 @@ export function useComponentState({
|
|||||||
});
|
});
|
||||||
return { deposit, uri: talerDepositUri, amount };
|
return { deposit, uri: talerDepositUri, amount };
|
||||||
});
|
});
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
if (!info) return { status: "loading", error: undefined };
|
if (!info) return { status: "loading", error: undefined };
|
||||||
if (info.hasError) {
|
if (info.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: info,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
info,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,12 +50,12 @@ describe("Deposit CTA states", () => {
|
|||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
},
|
},
|
||||||
({ status, error }) => {
|
({ status, error }) => {
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("error");
|
||||||
|
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
if (!error.hasError) expect.fail();
|
// if (!error.hasError) expect.fail();
|
||||||
if (error.operational) expect.fail();
|
// if (error.operational) expect.fail();
|
||||||
expect(error.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
|
expect(error.cause?.message).eq("ERROR_NO-URI-FOR-DEPOSIT");
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
TestingContext,
|
TestingContext,
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
@ -30,17 +29,6 @@ import { State } from "./index.js";
|
|||||||
* @author sebasjm
|
* @author sebasjm
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load deposit status</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView(state: State.Ready): VNode {
|
export function ReadyView(state: State.Ready): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
@ -55,7 +43,7 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
{Amounts.isNonZero(state.cost) && (
|
{Amounts.isNonZero(state.cost) && (
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Cost</i18n.Translate>}
|
title={i18n.str`Cost`}
|
||||||
text={<Amount value={state.cost} />}
|
text={<Amount value={state.cost} />}
|
||||||
kind="negative"
|
kind="negative"
|
||||||
/>
|
/>
|
||||||
@ -63,14 +51,14 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
{Amounts.isNonZero(state.fee) && (
|
{Amounts.isNonZero(state.fee) && (
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Fee</i18n.Translate>}
|
title={i18n.str`Fee`}
|
||||||
text={<Amount value={state.fee} />}
|
text={<Amount value={state.fee} />}
|
||||||
kind="negative"
|
kind="negative"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>To be received</i18n.Translate>}
|
title={i18n.str`To be received`}
|
||||||
text={<Amount value={state.effective} />}
|
text={<Amount value={state.effective} />}
|
||||||
kind="positive"
|
kind="positive"
|
||||||
/>
|
/>
|
||||||
|
@ -14,16 +14,17 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
|
import { AmountJson } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
||||||
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||||
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
amount: string;
|
amount: string;
|
||||||
@ -45,8 +46,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -63,13 +64,12 @@ export namespace State {
|
|||||||
requestAmount: AmountJson;
|
requestAmount: AmountJson;
|
||||||
exchangeUrl: string;
|
exchangeUrl: string;
|
||||||
error: undefined;
|
error: undefined;
|
||||||
operationError?: TalerErrorDetail;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"no-exchange": NoExchangesView,
|
"no-exchange": NoExchangesView,
|
||||||
"selecting-exchange": ExchangeSelectionPage,
|
"selecting-exchange": ExchangeSelectionPage,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
|
@ -23,7 +23,9 @@ import {
|
|||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { isFuture, parse } from "date-fns";
|
import { isFuture, parse } from "date-fns";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||||
import { RecursiveState } from "../../utils/index.js";
|
import { RecursiveState } from "../../utils/index.js";
|
||||||
@ -40,6 +42,7 @@ export function useComponentState({
|
|||||||
const hook = useAsyncAsHook(() =>
|
const hook = useAsyncAsHook(() =>
|
||||||
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
);
|
);
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
if (!hook) {
|
if (!hook) {
|
||||||
return {
|
return {
|
||||||
@ -49,10 +52,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (hook.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const exchangeList = hook.response.exchanges;
|
const exchangeList = hook.response.exchanges;
|
||||||
|
|
||||||
@ -60,10 +72,6 @@ export function useComponentState({
|
|||||||
const [subject, setSubject] = useState<string | undefined>();
|
const [subject, setSubject] = useState<string | undefined>();
|
||||||
const [timestamp, setTimestamp] = useState<string | undefined>();
|
const [timestamp, setTimestamp] = useState<string | undefined>();
|
||||||
|
|
||||||
const [operationError, setOperationError] = useState<
|
|
||||||
TalerErrorDetail | undefined
|
|
||||||
>(undefined);
|
|
||||||
|
|
||||||
const selectedExchange = useSelectedExchange({
|
const selectedExchange = useSelectedExchange({
|
||||||
currency: amount.currency,
|
currency: amount.currency,
|
||||||
defaultExchange: undefined,
|
defaultExchange: undefined,
|
||||||
@ -93,11 +101,19 @@ export function useComponentState({
|
|||||||
error: undefined,
|
error: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
}
|
}
|
||||||
|
|
||||||
const { amountEffective, amountRaw } = hook.response;
|
const { amountEffective, amountRaw } = hook.response;
|
||||||
@ -160,8 +176,8 @@ export function useComponentState({
|
|||||||
subject === undefined
|
subject === undefined
|
||||||
? undefined
|
? undefined
|
||||||
: !subject
|
: !subject
|
||||||
? "Can't be empty"
|
? "Can't be empty"
|
||||||
: undefined,
|
: undefined,
|
||||||
value: subject ?? "",
|
value: subject ?? "",
|
||||||
onInput: async (e) => setSubject(e),
|
onInput: async (e) => setSubject(e),
|
||||||
},
|
},
|
||||||
@ -183,7 +199,6 @@ export function useComponentState({
|
|||||||
requestAmount,
|
requestAmount,
|
||||||
toBeReceived,
|
toBeReceived,
|
||||||
error: undefined,
|
error: undefined,
|
||||||
operationError,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -17,41 +17,24 @@
|
|||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { QR } from "../../components/QR.js";
|
|
||||||
import {
|
import {
|
||||||
Link,
|
|
||||||
SubTitle,
|
SubTitle,
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
WalletAction,
|
WalletAction,
|
||||||
} from "../../components/styled/index.js";
|
} from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { Grid } from "../../mui/Grid.js";
|
|
||||||
import { TextField } from "../../mui/TextField.js";
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import editIcon from "../../svg/edit_24px.svg";
|
import editIcon from "../../svg/edit_24px.svg";
|
||||||
import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js";
|
import { ExchangeDetails, InvoiceDetails } from "../../wallet/Transaction.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({
|
export function ReadyView({
|
||||||
exchangeUrl,
|
exchangeUrl,
|
||||||
subject,
|
subject,
|
||||||
expiration,
|
expiration,
|
||||||
cancel,
|
|
||||||
operationError,
|
|
||||||
create,
|
create,
|
||||||
toBeReceived,
|
toBeReceived,
|
||||||
requestAmount,
|
requestAmount,
|
||||||
@ -59,7 +42,7 @@ export function ReadyView({
|
|||||||
}: State.Ready): VNode {
|
}: State.Ready): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
async function oneDayExpiration() {
|
async function oneDayExpiration(): Promise<void> {
|
||||||
if (expiration.onInput) {
|
if (expiration.onInput) {
|
||||||
expiration.onInput(
|
expiration.onInput(
|
||||||
format(new Date().getTime() + 1000 * 60 * 60 * 24, "dd/MM/yyyy"),
|
format(new Date().getTime() + 1000 * 60 * 60 * 24, "dd/MM/yyyy"),
|
||||||
@ -67,14 +50,14 @@ export function ReadyView({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function oneWeekExpiration() {
|
async function oneWeekExpiration(): Promise<void> {
|
||||||
if (expiration.onInput) {
|
if (expiration.onInput) {
|
||||||
expiration.onInput(
|
expiration.onInput(
|
||||||
format(new Date().getTime() + 1000 * 60 * 60 * 24 * 7, "dd/MM/yyyy"),
|
format(new Date().getTime() + 1000 * 60 * 60 * 24 * 7, "dd/MM/yyyy"),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function _20DaysExpiration() {
|
async function _20DaysExpiration(): Promise<void> {
|
||||||
if (expiration.onInput) {
|
if (expiration.onInput) {
|
||||||
expiration.onInput(
|
expiration.onInput(
|
||||||
format(new Date().getTime() + 1000 * 60 * 60 * 24 * 20, "dd/MM/yyyy"),
|
format(new Date().getTime() + 1000 * 60 * 60 * 24 * 20, "dd/MM/yyyy"),
|
||||||
@ -87,16 +70,6 @@ export function ReadyView({
|
|||||||
<SubTitle>
|
<SubTitle>
|
||||||
<i18n.Translate>Digital invoice</i18n.Translate>
|
<i18n.Translate>Digital invoice</i18n.Translate>
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
{operationError && (
|
|
||||||
<ErrorTalerOperation
|
|
||||||
title={
|
|
||||||
<i18n.Translate>
|
|
||||||
Could not finish the invoice creation
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={operationError}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<section style={{ textAlign: "left" }}>
|
<section style={{ textAlign: "left" }}>
|
||||||
<Part
|
<Part
|
||||||
title={
|
title={
|
||||||
@ -125,9 +98,7 @@ export function ReadyView({
|
|||||||
label="Subject"
|
label="Subject"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
error={subject.error}
|
error={subject.error}
|
||||||
helperText={
|
helperText={i18n.str`Short description of the invoice`}
|
||||||
<i18n.Translate>Short description of the invoice</i18n.Translate>
|
|
||||||
}
|
|
||||||
required
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
value={subject.value}
|
value={subject.value}
|
||||||
@ -171,7 +142,7 @@ export function ReadyView({
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<InvoiceDetails
|
<InvoiceDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -187,11 +158,6 @@ export function ReadyView({
|
|||||||
<i18n.Translate>Create</i18n.Translate>
|
<i18n.Translate>Create</i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={cancel.onClick}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,12 +20,13 @@ import {
|
|||||||
PreparePayResult,
|
PreparePayResult,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerPayPullUri: string;
|
talerPayPullUri: string;
|
||||||
@ -48,8 +49,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -83,7 +84,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"no-balance-for-currency": ReadyView,
|
"no-balance-for-currency": ReadyView,
|
||||||
"no-enough-balance": ReadyView,
|
"no-enough-balance": ReadyView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
|
@ -25,7 +25,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
|
const p2p = await api.wallet.call(WalletApiOperation.CheckPeerPullPayment, {
|
||||||
talerUri: talerPayPullUri,
|
talerUri: talerPayPullUri,
|
||||||
@ -63,10 +66,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (hook.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const { contractTerms, peerPullPaymentIncomingId } = hook.response.p2p;
|
const { contractTerms, peerPullPaymentIncomingId } = hook.response.p2p;
|
||||||
|
|
||||||
|
@ -17,26 +17,14 @@
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
|
import { PaymentButtons } from "../../components/PaymentButtons.js";
|
||||||
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
import { Time } from "../../components/Time.js";
|
import { Time } from "../../components/Time.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { PaymentButtons } from "../../components/PaymentButtons";
|
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView(
|
export function ReadyView(
|
||||||
state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
|
state: State.Ready | State.NoBalanceForCurrency | State.NoEnoughBalance,
|
||||||
): VNode {
|
): VNode {
|
||||||
@ -60,25 +48,15 @@ export function ReadyView(
|
|||||||
</SubTitle>
|
</SubTitle>
|
||||||
{operationError && (
|
{operationError && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={
|
title={i18n.str`Could not finish the payment operation`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not finish the payment operation
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={operationError}
|
error={operationError}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<section style={{ textAlign: "left" }}>
|
<section style={{ textAlign: "left" }}>
|
||||||
|
<Part title={i18n.str`Subject`} text={<div>{summary}</div>} />
|
||||||
|
<Part title={i18n.str`Amount`} text={<Amount value={amount} />} />
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Valid until`}
|
||||||
text={<div>{summary}</div>}
|
|
||||||
/>
|
|
||||||
<Part
|
|
||||||
title={<i18n.Translate>Amount</i18n.Translate>}
|
|
||||||
text={<Amount value={amount} />}
|
|
||||||
/>
|
|
||||||
<Part
|
|
||||||
title={<i18n.Translate>Valid until</i18n.Translate>}
|
|
||||||
text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
|
text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
@ -91,11 +69,6 @@ export function ReadyView(
|
|||||||
payHandler={status === "ready" ? state.accept : undefined}
|
payHandler={status === "ready" ? state.accept : undefined}
|
||||||
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
||||||
/>
|
/>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={cancel.onClick}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,12 +21,13 @@ import {
|
|||||||
PreparePayResultInsufficientBalance,
|
PreparePayResultInsufficientBalance,
|
||||||
PreparePayResultPaymentPossible,
|
PreparePayResultPaymentPossible,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { BaseView, LoadingUriView } from "./views.js";
|
import { BaseView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerPayUri?: string;
|
talerPayUri?: string;
|
||||||
@ -49,8 +50,8 @@ export namespace State {
|
|||||||
error: undefined;
|
error: undefined;
|
||||||
}
|
}
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseInfo {
|
interface BaseInfo {
|
||||||
@ -86,7 +87,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"no-balance-for-currency": BaseView,
|
"no-balance-for-currency": BaseView,
|
||||||
"no-enough-balance": BaseView,
|
"no-enough-balance": BaseView,
|
||||||
confirmed: BaseView,
|
confirmed: BaseView,
|
||||||
|
@ -23,7 +23,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
@ -36,6 +38,7 @@ export function useComponentState({
|
|||||||
}: Props): State {
|
}: Props): State {
|
||||||
const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined);
|
const [payErrMsg, setPayErrMsg] = useState<TalerError | undefined>(undefined);
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
if (!talerPayUri) throw Error("ERROR_NO-URI-FOR-PAYMENT");
|
||||||
@ -80,10 +83,19 @@ export function useComponentState({
|
|||||||
if (!hook) return { status: "loading", error: undefined };
|
if (!hook) return { status: "loading", error: undefined };
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (hook.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
const { payStatus } = hook.response;
|
const { payStatus } = hook.response;
|
||||||
|
|
||||||
const amount = Amounts.parseOrThrow(payStatus.amountRaw);
|
const amount = Amounts.parseOrThrow(payStatus.amountRaw);
|
||||||
|
@ -54,10 +54,10 @@ describe("Payment CTA states", () => {
|
|||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
},
|
},
|
||||||
({ status, error }) => {
|
({ status, error }) => {
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("error");
|
||||||
if (error === undefined) expect.fail();
|
if (error === undefined) expect.fail();
|
||||||
expect(error.hasError).true;
|
// expect(error.hasError).true;
|
||||||
expect(error.operational).false;
|
// expect(error.operational).false;
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
TestingContext,
|
TestingContext,
|
||||||
|
@ -19,28 +19,17 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
MerchantContractTerms as ContractTerms,
|
MerchantContractTerms as ContractTerms,
|
||||||
PreparePayResultType,
|
PreparePayResultType,
|
||||||
|
TranslatedString,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { PaymentButtons } from "../../components/PaymentButtons.js";
|
import { PaymentButtons } from "../../components/PaymentButtons.js";
|
||||||
import { Link, SuccessBox, WarningBox } from "../../components/styled/index.js";
|
import { SuccessBox, WarningBox } from "../../components/styled/index.js";
|
||||||
import { Time } from "../../components/Time.js";
|
import { Time } from "../../components/Time.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
|
import { MerchantDetails, PurchaseDetails } from "../../wallet/Transaction.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load pay status</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
type SupportedStates =
|
type SupportedStates =
|
||||||
| State.Ready
|
| State.Ready
|
||||||
| State.Confirmed
|
| State.Confirmed
|
||||||
@ -66,17 +55,17 @@ export function BaseView(state: SupportedStates): VNode {
|
|||||||
|
|
||||||
<section style={{ textAlign: "left" }}>
|
<section style={{ textAlign: "left" }}>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Purchase</i18n.Translate>}
|
title={i18n.str`Purchase`}
|
||||||
text={contractTerms.summary}
|
text={contractTerms.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant</i18n.Translate>}
|
title={i18n.str`Merchant`}
|
||||||
text={<MerchantDetails merchant={contractTerms.merchant} />}
|
text={<MerchantDetails merchant={contractTerms.merchant} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<PurchaseDetails
|
<PurchaseDetails
|
||||||
price={price}
|
price={price}
|
||||||
@ -93,14 +82,14 @@ export function BaseView(state: SupportedStates): VNode {
|
|||||||
/>
|
/>
|
||||||
{contractTerms.order_id && (
|
{contractTerms.order_id && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Receipt</i18n.Translate>}
|
title={i18n.str`Receipt`}
|
||||||
text={`#${contractTerms.order_id}`}
|
text={`#${contractTerms.order_id}` as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{contractTerms.pay_deadline && (
|
{contractTerms.pay_deadline && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Valid until</i18n.Translate>}
|
title={i18n.str`Valid until`}
|
||||||
text={
|
text={
|
||||||
<Time
|
<Time
|
||||||
timestamp={AbsoluteTime.fromTimestamp(
|
timestamp={AbsoluteTime.fromTimestamp(
|
||||||
@ -121,11 +110,6 @@ export function BaseView(state: SupportedStates): VNode {
|
|||||||
payHandler={state.status === "ready" ? state.payHandler : undefined}
|
payHandler={state.status === "ready" ? state.payHandler : undefined}
|
||||||
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
goToWalletManualWithdraw={state.goToWalletManualWithdraw}
|
||||||
/>
|
/>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={state.cancel}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerRecoveryUri?: string;
|
talerRecoveryUri?: string;
|
||||||
@ -36,8 +37,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -53,7 +54,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
import { parseRecoveryUri } from "@gnu-taler/taler-util";
|
import { parseRecoveryUri } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { Alert } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState({
|
export function useComponentState({
|
||||||
@ -25,13 +27,16 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
if (!talerRecoveryUri) {
|
if (!talerRecoveryUri) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: {
|
error: {
|
||||||
operational: false,
|
type: "error",
|
||||||
hasError: true,
|
message: i18n.str`Missing URI`,
|
||||||
message: "Missing URI",
|
description: i18n.str``,
|
||||||
|
cause: new Error("something"),
|
||||||
|
context: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -39,11 +44,13 @@ export function useComponentState({
|
|||||||
|
|
||||||
if (!info) {
|
if (!info) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: {
|
error: {
|
||||||
operational: false,
|
type: "error",
|
||||||
hasError: true,
|
message: i18n.str`Could not parse the recovery URI`,
|
||||||
message: "Could not be read",
|
description: i18n.str``,
|
||||||
|
cause: new Error("something"),
|
||||||
|
context: {},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -15,28 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={
|
|
||||||
<i18n.Translate>
|
|
||||||
Could not load backup recovery information
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({ accept, cancel }: State.Ready): VNode {
|
export function ReadyView({ accept, cancel }: State.Ready): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
|
@ -15,17 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson, Product } from "@gnu-taler/taler-util";
|
import { AmountJson, Product } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import {
|
import { IgnoredView, InProgressView, ReadyView } from "./views.js";
|
||||||
IgnoredView,
|
|
||||||
InProgressView,
|
|
||||||
LoadingUriView,
|
|
||||||
ReadyView,
|
|
||||||
} from "./views.js";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerRefundUri?: string;
|
talerRefundUri?: string;
|
||||||
@ -47,8 +43,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BaseInfo {
|
interface BaseInfo {
|
||||||
@ -81,7 +77,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"in-progress": InProgressView,
|
"in-progress": InProgressView,
|
||||||
ignored: IgnoredView,
|
ignored: IgnoredView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
|
import { Amounts, NotificationType } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -27,6 +29,7 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const [ignored, setIgnored] = useState(false);
|
const [ignored, setIgnored] = useState(false);
|
||||||
|
|
||||||
const info = useAsyncAsHook(async () => {
|
const info = useAsyncAsHook(async () => {
|
||||||
@ -49,10 +52,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (info.hasError) {
|
if (info.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: info,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
info,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (info.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: info,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const { refund, uri } = info.response;
|
const { refund, uri } = info.response;
|
||||||
|
|
||||||
|
@ -53,11 +53,11 @@ describe("Refund CTA states", () => {
|
|||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
},
|
},
|
||||||
({ status, error }) => {
|
({ status, error }) => {
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("error");
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
if (!error.hasError) expect.fail();
|
// if (!error.hasError) expect.fail();
|
||||||
if (error.operational) expect.fail();
|
// if (error.operational) expect.fail();
|
||||||
expect(error.message).eq("ERROR_NO-URI-FOR-REFUND");
|
expect(error.cause?.message).eq("ERROR_NO-URI-FOR-REFUND");
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
TestingContext,
|
TestingContext,
|
||||||
|
@ -17,26 +17,14 @@
|
|||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
|
import { ProductList } from "../../components/ProductList.js";
|
||||||
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { ProductList } from "../../components/ProductList.js";
|
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load refund status</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function IgnoredView(state: State.Ignored): VNode {
|
export function IgnoredView(state: State.Ignored): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
@ -73,13 +61,13 @@ export function InProgressView(state: State.InProgress): VNode {
|
|||||||
<section>
|
<section>
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Total to refund</i18n.Translate>}
|
title={i18n.str`Total to refund`}
|
||||||
text={<Amount value={state.awaitingAmount} />}
|
text={<Amount value={state.awaitingAmount} />}
|
||||||
kind="negative"
|
kind="negative"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Refunded</i18n.Translate>}
|
title={i18n.str`Refunded`}
|
||||||
text={<Amount value={state.amount} />}
|
text={<Amount value={state.amount} />}
|
||||||
kind="negative"
|
kind="negative"
|
||||||
/>
|
/>
|
||||||
@ -112,21 +100,21 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
<section>
|
<section>
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Order amount</i18n.Translate>}
|
title={i18n.str`Order amount`}
|
||||||
text={<Amount value={state.amount} />}
|
text={<Amount value={state.amount} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
{Amounts.isNonZero(state.granted) && (
|
{Amounts.isNonZero(state.granted) && (
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Already refunded</i18n.Translate>}
|
title={i18n.str`Already refunded`}
|
||||||
text={<Amount value={state.granted} />}
|
text={<Amount value={state.granted} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Refund offered</i18n.Translate>}
|
title={i18n.str`Refund offered`}
|
||||||
text={<Amount value={state.awaitingAmount} />}
|
text={<Amount value={state.awaitingAmount} />}
|
||||||
kind="positive"
|
kind="positive"
|
||||||
/>
|
/>
|
||||||
@ -147,11 +135,6 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={state.cancel}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,17 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson } from "@gnu-taler/taler-util";
|
import { AmountJson } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import {
|
import { AcceptedView, IgnoredView, ReadyView } from "./views.js";
|
||||||
AcceptedView,
|
|
||||||
IgnoredView,
|
|
||||||
LoadingUriView,
|
|
||||||
ReadyView,
|
|
||||||
} from "./views.js";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerTipUri?: string;
|
talerTipUri?: string;
|
||||||
@ -48,8 +44,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -75,7 +71,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
accepted: AcceptedView,
|
accepted: AcceptedView,
|
||||||
ignored: IgnoredView,
|
ignored: IgnoredView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
|
|
||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -26,6 +28,7 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const tipInfo = useAsyncAsHook(async () => {
|
const tipInfo = useAsyncAsHook(async () => {
|
||||||
if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
|
if (!talerTipUri) throw Error("ERROR_NO-URI-FOR-TIP");
|
||||||
const tip = await api.wallet.call(WalletApiOperation.PrepareTip, {
|
const tip = await api.wallet.call(WalletApiOperation.PrepareTip, {
|
||||||
@ -42,10 +45,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (tipInfo.hasError) {
|
if (tipInfo.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: tipInfo,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
tipInfo,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (tipInfo.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: tipInfo,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const { tip } = tipInfo.response;
|
const { tip } = tipInfo.response;
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ import { Amounts } from "@gnu-taler/taler-util";
|
|||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { expect } from "chai";
|
import { expect } from "chai";
|
||||||
import { tests } from "../../../../web-util/src/index.browser.js";
|
import { tests } from "../../../../web-util/src/index.browser.js";
|
||||||
import { mountHook, nullFunction } from "../../test-utils.js";
|
import { createWalletApiMock, nullFunction } from "../../test-utils.js";
|
||||||
import { createWalletApiMock } from "../../test-utils.js";
|
|
||||||
import { Props } from "./index.js";
|
import { Props } from "./index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
|
|
||||||
@ -47,11 +46,9 @@ describe("Tip CTA states", () => {
|
|||||||
expect(error).undefined;
|
expect(error).undefined;
|
||||||
},
|
},
|
||||||
({ status, error }) => {
|
({ status, error }) => {
|
||||||
expect(status).equals("loading-uri");
|
expect(status).equals("error");
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
if (!error.hasError) expect.fail();
|
expect(error.cause?.message).eq("ERROR_NO-URI-FOR-TIP");
|
||||||
if (error.operational) expect.fail();
|
|
||||||
expect(error.message).eq("ERROR_NO-URI-FOR-TIP");
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
TestingContext,
|
TestingContext,
|
||||||
|
@ -14,9 +14,9 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
@ -24,17 +24,6 @@ import { useTranslationContext } from "../../context/translation.js";
|
|||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load tip status</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function IgnoredView(state: State.Ignored): VNode {
|
export function IgnoredView(state: State.Ignored): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
@ -66,18 +55,18 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
<i18n.Translate>The merchant is offering you a tip</i18n.Translate>
|
<i18n.Translate>The merchant is offering you a tip</i18n.Translate>
|
||||||
</p>
|
</p>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Amount</i18n.Translate>}
|
title={i18n.str`Amount`}
|
||||||
text={<Amount value={state.amount} />}
|
text={<Amount value={state.amount} />}
|
||||||
kind="positive"
|
kind="positive"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant URL</i18n.Translate>}
|
title={i18n.str`Merchant URL`}
|
||||||
text={state.merchantBaseUrl}
|
text={state.merchantBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange</i18n.Translate>}
|
title={i18n.str`Exchange`}
|
||||||
text={state.exchangeBaseUrl}
|
text={state.exchangeBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
</section>
|
</section>
|
||||||
@ -92,11 +81,6 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={state.cancel.onClick}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,12 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
|
import { AmountJson, TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
amount: string;
|
amount: string;
|
||||||
@ -37,8 +38,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -59,7 +60,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ import {
|
|||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { isFuture, parse } from "date-fns";
|
import { isFuture, parse } from "date-fns";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ export function useComponentState({
|
|||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
const amount = Amounts.parseOrThrow(amountStr);
|
const amount = Amounts.parseOrThrow(amountStr);
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const [subject, setSubject] = useState<string | undefined>();
|
const [subject, setSubject] = useState<string | undefined>();
|
||||||
const [timestamp, setTimestamp] = useState<string | undefined>();
|
const [timestamp, setTimestamp] = useState<string | undefined>();
|
||||||
@ -59,10 +62,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (hook.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const { amountEffective, amountRaw } = hook.response;
|
const { amountEffective, amountRaw } = hook.response;
|
||||||
const debitAmount = Amounts.parseOrThrow(amountRaw);
|
const debitAmount = Amounts.parseOrThrow(amountRaw);
|
||||||
|
@ -17,10 +17,8 @@
|
|||||||
import { format } from "date-fns";
|
import { format } from "date-fns";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { QR } from "../../components/QR.js";
|
|
||||||
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
@ -28,17 +26,6 @@ import { TextField } from "../../mui/TextField.js";
|
|||||||
import { TransferDetails } from "../../wallet/Transaction.js";
|
import { TransferDetails } from "../../wallet/Transaction.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({
|
export function ReadyView({
|
||||||
subject,
|
subject,
|
||||||
expiration,
|
expiration,
|
||||||
@ -80,11 +67,7 @@ export function ReadyView({
|
|||||||
</SubTitle>
|
</SubTitle>
|
||||||
{operationError && (
|
{operationError && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={
|
title={i18n.str`Could not finish the transfer creation`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not finish the transfer creation
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={operationError}
|
error={operationError}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -93,9 +76,7 @@ export function ReadyView({
|
|||||||
<TextField
|
<TextField
|
||||||
label="Subject"
|
label="Subject"
|
||||||
variant="filled"
|
variant="filled"
|
||||||
helperText={
|
helperText={i18n.str`Short description of the transfer`}
|
||||||
<i18n.Translate>Short description of the transfer</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={subject.error}
|
error={subject.error}
|
||||||
required
|
required
|
||||||
fullWidth
|
fullWidth
|
||||||
@ -138,7 +119,7 @@ export function ReadyView({
|
|||||||
</p>
|
</p>
|
||||||
</p>
|
</p>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<TransferDetails
|
<TransferDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -154,13 +135,6 @@ export function ReadyView({
|
|||||||
<i18n.Translate>Create</i18n.Translate>
|
<i18n.Translate>Create</i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={cancel.onClick}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,13 @@ import {
|
|||||||
AmountJson,
|
AmountJson,
|
||||||
TalerErrorDetail,
|
TalerErrorDetail,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { ButtonHandler } from "../../mui/handlers.js";
|
import { ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
talerPayPushUri: string;
|
talerPayPushUri: string;
|
||||||
@ -41,8 +42,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-uri";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -62,7 +63,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-uri": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -22,7 +22,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
|
return await api.wallet.call(WalletApiOperation.CheckPeerPushPayment, {
|
||||||
talerUri: talerPayPushUri,
|
talerUri: talerPayPushUri,
|
||||||
@ -49,10 +52,19 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-uri",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the status of the term of service`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// if (hook.hasError) {
|
||||||
|
// return {
|
||||||
|
// status: "loading-uri",
|
||||||
|
// error: hook,
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
const { contractTerms, peerPushPaymentIncomingId } = hook.response;
|
const { contractTerms, peerPushPaymentIncomingId } = hook.response;
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { LogoHeader } from "../../components/LogoHeader.js";
|
import { LogoHeader } from "../../components/LogoHeader.js";
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
import { Link, SubTitle, WalletAction } from "../../components/styled/index.js";
|
||||||
@ -26,17 +25,6 @@ import { useTranslationContext } from "../../context/translation.js";
|
|||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({
|
export function ReadyView({
|
||||||
accept,
|
accept,
|
||||||
summary,
|
summary,
|
||||||
@ -54,25 +42,15 @@ export function ReadyView({
|
|||||||
</SubTitle>
|
</SubTitle>
|
||||||
{operationError && (
|
{operationError && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={
|
title={i18n.str`Could not finish the pickup operation`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not finish the pickup operation
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={operationError}
|
error={operationError}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<section style={{ textAlign: "left" }}>
|
<section style={{ textAlign: "left" }}>
|
||||||
|
<Part title={i18n.str`Subject`} text={<div>{summary}</div>} />
|
||||||
|
<Part title={i18n.str`Amount`} text={<Amount value={amount} />} />
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Valid until`}
|
||||||
text={<div>{summary}</div>}
|
|
||||||
/>
|
|
||||||
<Part
|
|
||||||
title={<i18n.Translate>Amount</i18n.Translate>}
|
|
||||||
text={<Amount value={amount} />}
|
|
||||||
/>
|
|
||||||
<Part
|
|
||||||
title={<i18n.Translate>Valid until</i18n.Translate>}
|
|
||||||
text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
|
text={<Time timestamp={expiration} format="dd MMMM yyyy, HH:mm" />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
@ -84,11 +62,6 @@ export function ReadyView({
|
|||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
</Button>
|
</Button>
|
||||||
</section>
|
</section>
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={cancel.onClick}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,9 @@ import {
|
|||||||
|
|
||||||
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
import { ExchangeSelectionPage } from "../../wallet/ExchangeSelection/index.js";
|
||||||
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
import { NoExchangesView } from "../../wallet/ExchangeSelection/views.js";
|
||||||
import { LoadingInfoView, LoadingUriView, SuccessView } from "./views.js";
|
import { SuccessView } from "./views.js";
|
||||||
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
|
|
||||||
export interface PropsFromURI {
|
export interface PropsFromURI {
|
||||||
talerWithdrawUri: string | undefined;
|
talerWithdrawUri: string | undefined;
|
||||||
@ -44,7 +46,6 @@ export interface PropsFromParams {
|
|||||||
export type State =
|
export type State =
|
||||||
| State.Loading
|
| State.Loading
|
||||||
| State.LoadingUriError
|
| State.LoadingUriError
|
||||||
| State.LoadingInfoError
|
|
||||||
| SelectExchangeState.NoExchange
|
| SelectExchangeState.NoExchange
|
||||||
| SelectExchangeState.Selecting
|
| SelectExchangeState.Selecting
|
||||||
| State.Success;
|
| State.Success;
|
||||||
@ -55,12 +56,8 @@ export namespace State {
|
|||||||
error: undefined;
|
error: undefined;
|
||||||
}
|
}
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "uri-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
|
||||||
export interface LoadingInfoError {
|
|
||||||
status: "amount-error";
|
|
||||||
error: HookError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Success = {
|
export type Success = {
|
||||||
@ -86,8 +83,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"uri-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"amount-error": LoadingInfoView,
|
|
||||||
"no-exchange": NoExchangesView,
|
"no-exchange": NoExchangesView,
|
||||||
"selecting-exchange": ExchangeSelectionPage,
|
"selecting-exchange": ExchangeSelectionPage,
|
||||||
success: SuccessView,
|
success: SuccessView,
|
||||||
|
@ -23,7 +23,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { TalerError, WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
import { useSelectedExchange } from "../../hooks/useSelectedExchange.js";
|
||||||
import { RecursiveState } from "../../utils/index.js";
|
import { RecursiveState } from "../../utils/index.js";
|
||||||
@ -35,6 +37,7 @@ export function useComponentStateFromParams({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: PropsFromParams): RecursiveState<State> {
|
}: PropsFromParams): RecursiveState<State> {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const uriInfoHook = useAsyncAsHook(async () => {
|
const uriInfoHook = useAsyncAsHook(async () => {
|
||||||
const exchanges = await api.wallet.call(
|
const exchanges = await api.wallet.call(
|
||||||
WalletApiOperation.ListExchanges,
|
WalletApiOperation.ListExchanges,
|
||||||
@ -47,8 +50,11 @@ export function useComponentStateFromParams({
|
|||||||
|
|
||||||
if (uriInfoHook.hasError) {
|
if (uriInfoHook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "uri-error",
|
status: "error",
|
||||||
error: uriInfoHook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the list of exchanges`,
|
||||||
|
uriInfoHook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,6 +101,7 @@ export function useComponentStateFromURI({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: PropsFromURI): RecursiveState<State> {
|
}: PropsFromURI): RecursiveState<State> {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
/**
|
/**
|
||||||
* Ask the wallet about the withdraw URI
|
* Ask the wallet about the withdraw URI
|
||||||
*/
|
*/
|
||||||
@ -123,8 +130,11 @@ export function useComponentStateFromURI({
|
|||||||
|
|
||||||
if (uriInfoHook.hasError) {
|
if (uriInfoHook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "uri-error",
|
status: "error",
|
||||||
error: uriInfoHook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load info from URI`,
|
||||||
|
uriInfoHook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,6 +204,7 @@ function exchangeSelectionState(
|
|||||||
}
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const [ageRestricted, setAgeRestricted] = useState(0);
|
const [ageRestricted, setAgeRestricted] = useState(0);
|
||||||
const currentExchange = selectedExchange.selected;
|
const currentExchange = selectedExchange.selected;
|
||||||
const tosNeedToBeAccepted =
|
const tosNeedToBeAccepted =
|
||||||
@ -255,8 +266,11 @@ function exchangeSelectionState(
|
|||||||
}
|
}
|
||||||
if (amountHook.hasError) {
|
if (amountHook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "amount-error",
|
status: "error",
|
||||||
error: amountHook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load the withdrawal details`,
|
||||||
|
amountHook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!amountHook.response) {
|
if (!amountHook.response) {
|
||||||
|
@ -84,11 +84,11 @@ describe("Withdraw CTA states", () => {
|
|||||||
expect(status).equals("loading");
|
expect(status).equals("loading");
|
||||||
},
|
},
|
||||||
({ status, error }) => {
|
({ status, error }) => {
|
||||||
if (status != "uri-error") expect.fail();
|
if (status != "error") expect.fail();
|
||||||
if (!error) expect.fail();
|
if (!error) expect.fail();
|
||||||
if (!error.hasError) expect.fail();
|
// if (!error.hasError) expect.fail();
|
||||||
if (error.operational) expect.fail();
|
// if (error.operational) expect.fail();
|
||||||
expect(error.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL");
|
expect(error.cause?.message).eq("ERROR_NO-URI-FOR-WITHDRAWAL");
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
TestingContext,
|
TestingContext,
|
||||||
|
@ -19,16 +19,10 @@ import { Fragment, h, VNode } from "preact";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
import { ErrorTalerOperation } from "../../components/ErrorTalerOperation.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { Part } from "../../components/Part.js";
|
import { Part } from "../../components/Part.js";
|
||||||
import { QR } from "../../components/QR.js";
|
import { QR } from "../../components/QR.js";
|
||||||
import { SelectList } from "../../components/SelectList.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import {
|
import { Input, LinkSuccess, SvgIcon } from "../../components/styled/index.js";
|
||||||
Input,
|
|
||||||
Link,
|
|
||||||
LinkSuccess,
|
|
||||||
SvgIcon,
|
|
||||||
} from "../../components/styled/index.js";
|
|
||||||
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
@ -36,30 +30,6 @@ import editIcon from "../../svg/edit_24px.svg";
|
|||||||
import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
|
import { ExchangeDetails, WithdrawDetails } from "../../wallet/Transaction.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={
|
|
||||||
<i18n.Translate>Could not get the info from the URI</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function LoadingInfoView({ error }: State.LoadingInfoError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not get info of withdrawal</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SuccessView(state: State.Success): VNode {
|
export function SuccessView(state: State.Success): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
const currentTosVersionIsAccepted =
|
const currentTosVersionIsAccepted =
|
||||||
@ -68,11 +38,7 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
<Fragment>
|
<Fragment>
|
||||||
{state.doWithdrawal.error && (
|
{state.doWithdrawal.error && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={
|
title={i18n.str`Could not finish the withdrawal operation`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not finish the withdrawal operation
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={state.doWithdrawal.error.errorDetail}
|
error={state.doWithdrawal.error.errorDetail}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -103,7 +69,7 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
big
|
big
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<WithdrawDetails
|
<WithdrawDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -116,7 +82,7 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
{state.ageRestriction && (
|
{state.ageRestriction && (
|
||||||
<Input>
|
<Input>
|
||||||
<SelectList
|
<SelectList
|
||||||
label={<i18n.Translate>Age restriction</i18n.Translate>}
|
label={i18n.str`Age restriction`}
|
||||||
list={state.ageRestriction.list}
|
list={state.ageRestriction.list}
|
||||||
name="age"
|
name="age"
|
||||||
value={state.ageRestriction.value}
|
value={state.ageRestriction.value}
|
||||||
@ -148,11 +114,6 @@ export function SuccessView(state: State.Success): VNode {
|
|||||||
{state.talerWithdrawUri ? (
|
{state.talerWithdrawUri ? (
|
||||||
<WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
|
<WithdrawWithMobile talerWithdrawUri={state.talerWithdrawUri} />
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<section>
|
|
||||||
<Link upperCased onClick={state.cancel}>
|
|
||||||
<i18n.Translate>Cancel</i18n.Translate>
|
|
||||||
</Link>
|
|
||||||
</section>
|
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -168,11 +129,7 @@ function WithdrawWithMobile({
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
<LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
|
||||||
{!showQR ? (
|
{!showQR ? i18n.str`Withdraw to a mobile phone` : i18n.str`Hide QR`}
|
||||||
<i18n.Translate>Withdraw to a mobile phone</i18n.Translate>
|
|
||||||
) : (
|
|
||||||
<i18n.Translate>Hide QR</i18n.Translate>
|
|
||||||
)}
|
|
||||||
</LinkSuccess>
|
</LinkSuccess>
|
||||||
{showQR && (
|
{showQR && (
|
||||||
<div>
|
<div>
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||||
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
import { TalerError } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useEffect, useMemo, useState } from "preact/hooks";
|
import { useEffect, useMemo, useState } from "preact/hooks";
|
||||||
|
import { WalletError } from "../wxApi.js";
|
||||||
|
|
||||||
export interface HookOk<T> {
|
export interface HookOk<T> {
|
||||||
hasError: false;
|
hasError: false;
|
||||||
@ -26,13 +27,14 @@ export type HookError = HookGenericError | HookOperationalError;
|
|||||||
|
|
||||||
export interface HookGenericError {
|
export interface HookGenericError {
|
||||||
hasError: true;
|
hasError: true;
|
||||||
operational: false;
|
type: "error";
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface HookOperationalError {
|
export interface HookOperationalError {
|
||||||
hasError: true;
|
hasError: true;
|
||||||
operational: true;
|
type: "taler";
|
||||||
|
message: string;
|
||||||
details: TalerErrorDetail;
|
details: TalerErrorDetail;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,13 +70,21 @@ export function useAsyncAsHook<T>(
|
|||||||
if (e instanceof TalerError) {
|
if (e instanceof TalerError) {
|
||||||
setHookResponse({
|
setHookResponse({
|
||||||
hasError: true,
|
hasError: true,
|
||||||
operational: true,
|
type: "taler",
|
||||||
|
message: e.message,
|
||||||
details: e.errorDetail,
|
details: e.errorDetail,
|
||||||
});
|
});
|
||||||
|
} else if (e instanceof WalletError) {
|
||||||
|
setHookResponse({
|
||||||
|
hasError: true,
|
||||||
|
type: "taler",
|
||||||
|
message: e.message,
|
||||||
|
details: e.errorDetail.errorDetail,
|
||||||
|
});
|
||||||
} else if (e instanceof Error) {
|
} else if (e instanceof Error) {
|
||||||
setHookResponse({
|
setHookResponse({
|
||||||
hasError: true,
|
hasError: true,
|
||||||
operational: false,
|
type: "error",
|
||||||
message: e.message,
|
message: e.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { useNotNullLocalStorage } from "./useLocalStorage.js";
|
import { useNotNullLocalStorage } from "./useLocalStorage.js";
|
||||||
|
|
||||||
function getBrowserLang(): string | undefined {
|
function getBrowserLang(): string | undefined {
|
||||||
|
if (typeof window === "undefined") return undefined;
|
||||||
if (window.navigator.languages) return window.navigator.languages[0];
|
if (window.navigator.languages) return window.navigator.languages[0];
|
||||||
if (window.navigator.language) return window.navigator.language;
|
if (window.navigator.language) return window.navigator.language;
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -75,6 +75,9 @@ export function useNotNullLocalStorage(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const isSaved = window.localStorage.getItem(key) !== null;
|
const isSaved =
|
||||||
|
typeof window === "undefined"
|
||||||
|
? false
|
||||||
|
: window.localStorage.getItem(key) !== null;
|
||||||
return [storedValue, setValue, isSaved];
|
return [storedValue, setValue, isSaved];
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
* @author Sebastian Javier Marchano (sebasjm)
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
import { Alert } from "./Alert.jsx";
|
import { Alert } from "./Alert.jsx";
|
||||||
@ -53,16 +54,16 @@ export const BasicExample = (): VNode => (
|
|||||||
|
|
||||||
export const WithTitle = (): VNode => (
|
export const WithTitle = (): VNode => (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Alert title="Warning" severity="warning">
|
<Alert title={"Warning" as TranslatedString} severity="warning">
|
||||||
this is an warning
|
this is an warning
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Error" severity="error">
|
<Alert title={"Error" as TranslatedString} severity="error">
|
||||||
this is an error
|
this is an error
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Success" severity="success">
|
<Alert title={"Success" as TranslatedString} severity="success">
|
||||||
this is an success
|
this is an success
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Info" severity="info">
|
<Alert title={"Info" as TranslatedString} severity="info">
|
||||||
this is an info
|
this is an info
|
||||||
</Alert>
|
</Alert>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
@ -74,16 +75,32 @@ const showSomething = async function (): Promise<void> {
|
|||||||
|
|
||||||
export const WithAction = (): VNode => (
|
export const WithAction = (): VNode => (
|
||||||
<Wrapper>
|
<Wrapper>
|
||||||
<Alert title="Warning" severity="warning" onClose={showSomething}>
|
<Alert
|
||||||
|
title={"Warning" as TranslatedString}
|
||||||
|
severity="warning"
|
||||||
|
onClose={showSomething}
|
||||||
|
>
|
||||||
this is an warning
|
this is an warning
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Error" severity="error" onClose={showSomething}>
|
<Alert
|
||||||
|
title={"Error" as TranslatedString}
|
||||||
|
severity="error"
|
||||||
|
onClose={showSomething}
|
||||||
|
>
|
||||||
this is an error
|
this is an error
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Success" severity="success" onClose={showSomething}>
|
<Alert
|
||||||
|
title={"Success" as TranslatedString}
|
||||||
|
severity="success"
|
||||||
|
onClose={showSomething}
|
||||||
|
>
|
||||||
this is an success
|
this is an success
|
||||||
</Alert>
|
</Alert>
|
||||||
<Alert title="Info" severity="info" onClose={showSomething}>
|
<Alert
|
||||||
|
title={"Info" as TranslatedString}
|
||||||
|
severity="info"
|
||||||
|
onClose={showSomething}
|
||||||
|
>
|
||||||
this is an info
|
this is an info
|
||||||
</Alert>
|
</Alert>
|
||||||
</Wrapper>
|
</Wrapper>
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
You should have received a copy of the GNU General Public License along with
|
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/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
import { TranslatedString } from "@gnu-taler/taler-util";
|
||||||
import { css } from "@linaria/core";
|
import { css } from "@linaria/core";
|
||||||
import { ComponentChildren, h, VNode } from "preact";
|
import { ComponentChildren, h, VNode } from "preact";
|
||||||
// eslint-disable-next-line import/extensions
|
// eslint-disable-next-line import/extensions
|
||||||
@ -61,7 +62,7 @@ const colorVariant = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: TranslatedString;
|
||||||
variant?: "filled" | "outlined" | "standard";
|
variant?: "filled" | "outlined" | "standard";
|
||||||
role?: string;
|
role?: string;
|
||||||
onClose?: () => Promise<void>;
|
onClose?: () => Promise<void>;
|
||||||
@ -110,20 +111,20 @@ function Message({
|
|||||||
title,
|
title,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
title?: string;
|
title?: TranslatedString;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
class={css`
|
class={css`
|
||||||
padding: 8px 0px;
|
padding: 8px 0px;
|
||||||
width: 100%;
|
width: 90%;
|
||||||
`}
|
`}
|
||||||
>
|
>
|
||||||
{title && (
|
{title && (
|
||||||
<Typography
|
<Typography
|
||||||
class={css`
|
class={css`
|
||||||
font-weight: ${theme.typography.fontWeightMedium};
|
font-weight: ${theme.typography.fontWeightBold};
|
||||||
`}
|
`}
|
||||||
gutterBottom
|
gutterBottom
|
||||||
>
|
>
|
||||||
@ -160,6 +161,7 @@ export function Alert({
|
|||||||
"--color-main": theme.palette[severity].main,
|
"--color-main": theme.palette[severity].main,
|
||||||
"--color-light": theme.palette[severity].light,
|
"--color-light": theme.palette[severity].light,
|
||||||
// ...(style as any),
|
// ...(style as any),
|
||||||
|
textAlign: "left",
|
||||||
}}
|
}}
|
||||||
elevation={1}
|
elevation={1}
|
||||||
>
|
>
|
||||||
|
@ -29,9 +29,6 @@ const borderVariant = {
|
|||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
const baseStyle = css`
|
const baseStyle = css`
|
||||||
background-color: ${theme.palette.background.paper};
|
|
||||||
color: ${theme.palette.text.primary};
|
|
||||||
|
|
||||||
.theme-dark & {
|
.theme-dark & {
|
||||||
background-image: var(--gradient-white-elevation);
|
background-image: var(--gradient-white-elevation);
|
||||||
}
|
}
|
||||||
|
@ -57,7 +57,7 @@ export function hexToRgb(color: string): string {
|
|||||||
let colors = color.match(re);
|
let colors = color.match(re);
|
||||||
|
|
||||||
if (colors && colors[0].length === 1) {
|
if (colors && colors[0].length === 1) {
|
||||||
colors = colors.map((n) => n + n);
|
colors = colors.map((n) => n + n) as RegExpMatchArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
return colors
|
return colors
|
||||||
|
@ -146,9 +146,9 @@ export interface BackgroundPlatformAPI {
|
|||||||
*/
|
*/
|
||||||
getPermissionsApi(): CrossBrowserPermissionsApi;
|
getPermissionsApi(): CrossBrowserPermissionsApi;
|
||||||
/**
|
/**
|
||||||
* Used by the wallet backend to send notification about new information
|
* Used by the wallet backend to send notification about new information
|
||||||
* @param message
|
* @param message
|
||||||
*/
|
*/
|
||||||
sendMessageToAllChannels(message: MessageFromBackend): void;
|
sendMessageToAllChannels(message: MessageFromBackend): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -196,7 +196,6 @@ export interface ForegroundPlatformAPI {
|
|||||||
*/
|
*/
|
||||||
openWalletURIFromPopup(talerUri: string): void;
|
openWalletURIFromPopup(talerUri: string): void;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Popup API
|
* Popup API
|
||||||
*
|
*
|
||||||
@ -248,5 +247,4 @@ export interface ForegroundPlatformAPI {
|
|||||||
listenToWalletBackground(
|
listenToWalletBackground(
|
||||||
listener: (message: MessageFromBackend) => void,
|
listener: (message: MessageFromBackend) => void,
|
||||||
): () => void;
|
): () => void;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -14,17 +14,17 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { classifyTalerUri, Logger, TalerUriType } from "@gnu-taler/taler-util";
|
||||||
classifyTalerUri, Logger,
|
|
||||||
TalerUriType
|
|
||||||
} from "@gnu-taler/taler-util";
|
|
||||||
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
|
import { WalletOperations } from "@gnu-taler/taler-wallet-core";
|
||||||
import { BackgroundOperations } from "../wxApi.js";
|
import { BackgroundOperations } from "../wxApi.js";
|
||||||
import {
|
import {
|
||||||
BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, MessageFromBackend,
|
BackgroundPlatformAPI,
|
||||||
|
CrossBrowserPermissionsApi,
|
||||||
|
ForegroundPlatformAPI,
|
||||||
|
MessageFromBackend,
|
||||||
MessageFromFrontend,
|
MessageFromFrontend,
|
||||||
MessageResponse,
|
MessageResponse,
|
||||||
Permissions
|
Permissions,
|
||||||
} from "./api.js";
|
} from "./api.js";
|
||||||
|
|
||||||
const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
|
const api: BackgroundPlatformAPI & ForegroundPlatformAPI = {
|
||||||
@ -306,13 +306,12 @@ function openWalletPageFromPopup(page: string): void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let nextMessageIndex = 0;
|
let nextMessageIndex = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* To be used by the foreground
|
* To be used by the foreground
|
||||||
* @param message
|
* @param message
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
async function sendMessageToBackground<
|
async function sendMessageToBackground<
|
||||||
Op extends WalletOperations | BackgroundOperations,
|
Op extends WalletOperations | BackgroundOperations,
|
||||||
@ -321,13 +320,13 @@ async function sendMessageToBackground<
|
|||||||
|
|
||||||
return new Promise<any>((resolve, reject) => {
|
return new Promise<any>((resolve, reject) => {
|
||||||
logger.trace("send operation to the wallet background", message);
|
logger.trace("send operation to the wallet background", message);
|
||||||
let timedout = false
|
let timedout = false;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
timedout = true
|
timedout = true;
|
||||||
reject("timedout")
|
reject("timedout");
|
||||||
}, 2000);
|
}, 2000);
|
||||||
chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
|
chrome.runtime.sendMessage(messageWithId, (backgroundResponse) => {
|
||||||
if (timedout) return false
|
if (timedout) return false;
|
||||||
if (chrome.runtime.lastError) {
|
if (chrome.runtime.lastError) {
|
||||||
reject(chrome.runtime.lastError.message);
|
reject(chrome.runtime.lastError.message);
|
||||||
} else {
|
} else {
|
||||||
@ -358,7 +357,6 @@ function listenToWalletBackground(listener: (m: any) => void): () => void {
|
|||||||
|
|
||||||
const allPorts: chrome.runtime.Port[] = [];
|
const allPorts: chrome.runtime.Port[] = [];
|
||||||
|
|
||||||
|
|
||||||
function sendMessageToAllChannels(message: MessageFromBackend): void {
|
function sendMessageToAllChannels(message: MessageFromBackend): void {
|
||||||
for (const notif of allPorts) {
|
for (const notif of allPorts) {
|
||||||
// const message: MessageFromBackend = { type: msg.type };
|
// const message: MessageFromBackend = { type: msg.type };
|
||||||
@ -578,26 +576,26 @@ function setAlertedIcon(): void {
|
|||||||
|
|
||||||
interface OffscreenCanvasRenderingContext2D
|
interface OffscreenCanvasRenderingContext2D
|
||||||
extends CanvasState,
|
extends CanvasState,
|
||||||
CanvasTransform,
|
CanvasTransform,
|
||||||
CanvasCompositing,
|
CanvasCompositing,
|
||||||
CanvasImageSmoothing,
|
CanvasImageSmoothing,
|
||||||
CanvasFillStrokeStyles,
|
CanvasFillStrokeStyles,
|
||||||
CanvasShadowStyles,
|
CanvasShadowStyles,
|
||||||
CanvasFilters,
|
CanvasFilters,
|
||||||
CanvasRect,
|
CanvasRect,
|
||||||
CanvasDrawPath,
|
CanvasDrawPath,
|
||||||
CanvasUserInterface,
|
CanvasUserInterface,
|
||||||
CanvasText,
|
CanvasText,
|
||||||
CanvasDrawImage,
|
CanvasDrawImage,
|
||||||
CanvasImageData,
|
CanvasImageData,
|
||||||
CanvasPathDrawingStyles,
|
CanvasPathDrawingStyles,
|
||||||
CanvasTextDrawingStyles,
|
CanvasTextDrawingStyles,
|
||||||
CanvasPath {
|
CanvasPath {
|
||||||
readonly canvas: OffscreenCanvas;
|
readonly canvas: OffscreenCanvas;
|
||||||
}
|
}
|
||||||
declare const OffscreenCanvasRenderingContext2D: {
|
declare const OffscreenCanvasRenderingContext2D: {
|
||||||
prototype: OffscreenCanvasRenderingContext2D;
|
prototype: OffscreenCanvasRenderingContext2D;
|
||||||
new(): OffscreenCanvasRenderingContext2D;
|
new (): OffscreenCanvasRenderingContext2D;
|
||||||
};
|
};
|
||||||
|
|
||||||
interface OffscreenCanvas extends EventTarget {
|
interface OffscreenCanvas extends EventTarget {
|
||||||
@ -610,7 +608,7 @@ interface OffscreenCanvas extends EventTarget {
|
|||||||
}
|
}
|
||||||
declare const OffscreenCanvas: {
|
declare const OffscreenCanvas: {
|
||||||
prototype: OffscreenCanvas;
|
prototype: OffscreenCanvas;
|
||||||
new(width: number, height: number): OffscreenCanvas;
|
new (width: number, height: number): OffscreenCanvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
function createCanvas(size: number): OffscreenCanvas {
|
function createCanvas(size: number): OffscreenCanvas {
|
||||||
|
@ -14,7 +14,12 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { BackgroundPlatformAPI, CrossBrowserPermissionsApi, ForegroundPlatformAPI, Permissions } from "./api.js";
|
import {
|
||||||
|
BackgroundPlatformAPI,
|
||||||
|
CrossBrowserPermissionsApi,
|
||||||
|
ForegroundPlatformAPI,
|
||||||
|
Permissions,
|
||||||
|
} from "./api.js";
|
||||||
import chromePlatform, {
|
import chromePlatform, {
|
||||||
containsHostPermissions as chromeHostContains,
|
containsHostPermissions as chromeHostContains,
|
||||||
removeHostPermissions as chromeHostRemove,
|
removeHostPermissions as chromeHostRemove,
|
||||||
|
@ -19,12 +19,13 @@ import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { BalanceTable } from "../components/BalanceTable.js";
|
import { BalanceTable } from "../components/BalanceTable.js";
|
||||||
|
import { ErrorAlertView } from "../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { MultiActionButton } from "../components/MultiActionButton.js";
|
import { MultiActionButton } from "../components/MultiActionButton.js";
|
||||||
|
import { alertFromError, ErrorAlert } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
import { Button } from "../mui/Button.js";
|
import { Button } from "../mui/Button.js";
|
||||||
import { ButtonHandler } from "../mui/handlers.js";
|
import { ButtonHandler } from "../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../utils/index.js";
|
import { compose, StateViewMap } from "../utils/index.js";
|
||||||
@ -47,7 +48,7 @@ export namespace State {
|
|||||||
|
|
||||||
export interface Error {
|
export interface Error {
|
||||||
status: "error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Action {
|
export interface Action {
|
||||||
@ -73,6 +74,7 @@ function useComponentState({
|
|||||||
goToWalletManualWithdraw,
|
goToWalletManualWithdraw,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const [addingAction, setAddingAction] = useState(false);
|
const [addingAction, setAddingAction] = useState(false);
|
||||||
const state = useAsyncAsHook(() =>
|
const state = useAsyncAsHook(() =>
|
||||||
api.wallet.call(WalletApiOperation.GetBalances, {}),
|
api.wallet.call(WalletApiOperation.GetBalances, {}),
|
||||||
@ -94,7 +96,7 @@ function useComponentState({
|
|||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "error",
|
status: "error",
|
||||||
error: state,
|
error: alertFromError(i18n.str`Could not load the balance`, state),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (addingAction) {
|
if (addingAction) {
|
||||||
@ -123,7 +125,7 @@ function useComponentState({
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
error: ErrorView,
|
error: ErrorAlertView,
|
||||||
action: ActionView,
|
action: ActionView,
|
||||||
balance: BalanceView,
|
balance: BalanceView,
|
||||||
};
|
};
|
||||||
@ -134,16 +136,6 @@ export const BalancePage = compose(
|
|||||||
viewMapping,
|
viewMapping,
|
||||||
);
|
);
|
||||||
|
|
||||||
function ErrorView({ error }: State.Error): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load balance page</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ActionView({ cancel }: State.Action): VNode {
|
function ActionView({ cancel }: State.Action): VNode {
|
||||||
return <AddNewActionView onCancel={cancel.onClick!} />;
|
return <AddNewActionView onCancel={cancel.onClick!} />;
|
||||||
}
|
}
|
||||||
@ -179,7 +171,7 @@ export function BalanceView(state: State.Balances): VNode {
|
|||||||
</Button>
|
</Button>
|
||||||
{currencyWithNonZeroAmount.length > 0 && (
|
{currencyWithNonZeroAmount.length > 0 && (
|
||||||
<MultiActionButton
|
<MultiActionButton
|
||||||
label={(s) => <i18n.Translate>Send {s}</i18n.Translate>}
|
label={(s) => i18n.str`Send ${s}`}
|
||||||
actions={currencyWithNonZeroAmount}
|
actions={currencyWithNonZeroAmount}
|
||||||
onClick={(c) => state.goToWalletDeposit(c)}
|
onClick={(c) => state.goToWalletDeposit(c)}
|
||||||
/>
|
/>
|
||||||
|
@ -33,7 +33,7 @@ export function NoBalanceHelp({
|
|||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
<Paper class={margin}>
|
<Paper class={margin}>
|
||||||
<Alert title="Your wallet is empty." severity="info">
|
<Alert title={i18n.str`Your wallet is empty.`} severity="info">
|
||||||
<Button
|
<Button
|
||||||
fullWidth
|
fullWidth
|
||||||
color="info"
|
color="info"
|
||||||
|
12
packages/taler-wallet-webextension/src/svg/progress.svg
Normal file
12
packages/taler-wallet-webextension/src/svg/progress.svg
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:#fff;display:block;" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||||
|
<defs>
|
||||||
|
<clipPath id="progress-cp" x="0" y="0" width="100" height="100">
|
||||||
|
<rect x="0" y="0" width="0" height="100">
|
||||||
|
<animate attributeName="width" repeatCount="indefinite" dur="2s" values="0;100;100" keyTimes="0;0.5;1"></animate>
|
||||||
|
<animate attributeName="x" repeatCount="indefinite" dur="2s" values="0;0;100" keyTimes="0;0.5;1"></animate>
|
||||||
|
</rect>
|
||||||
|
</clipPath>
|
||||||
|
</defs>
|
||||||
|
<path fill="none" stroke="darkgrey" stroke-width="1.04" d="M10.000000000000004 44.019999999999996L89.99999999999999 44.019999999999996A5.98 5.98 0 0 1 95.97999999999999 50L95.97999999999999 50A5.98 5.98 0 0 1 89.99999999999999 55.980000000000004L10.000000000000004 55.980000000000004A5.98 5.98 0 0 1 4.020000000000003 50L4.020000000000003 50A5.98 5.98 0 0 1 10.000000000000004 44.019999999999996 Z"></path>
|
||||||
|
<path fill="#0042b2" clip-path="url(#progress-cp)" d="M10.000000000000004 45.54L90 45.54A4.460000000000001 4.460000000000001 0 0 1 94.46 50L94.46 50A4.460000000000001 4.460000000000001 0 0 1 90 54.46L10.000000000000004 54.46A4.460000000000001 4.460000000000001 0 0 1 5.540000000000003 50L5.540000000000003 50A4.460000000000001 4.460000000000001 0 0 1 10.000000000000004 45.54 Z"></path>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.4 KiB |
@ -32,6 +32,7 @@ import {
|
|||||||
} from "preact";
|
} from "preact";
|
||||||
import { render as renderToString } from "preact-render-to-string";
|
import { render as renderToString } from "preact-render-to-string";
|
||||||
import { BackendProvider } from "./context/backend.js";
|
import { BackendProvider } from "./context/backend.js";
|
||||||
|
import { TranslationProvider } from "./context/translation.js";
|
||||||
import { BackgroundApiClient, wxApi } from "./wxApi.js";
|
import { BackgroundApiClient, wxApi } from "./wxApi.js";
|
||||||
|
|
||||||
// When doing tests we want the requestAnimationFrame to be as fast as possible.
|
// When doing tests we want the requestAnimationFrame to be as fast as possible.
|
||||||
@ -359,10 +360,12 @@ export function createWalletApiMock(): {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function TestingContext({
|
function TestingContext({
|
||||||
children,
|
children: _cs,
|
||||||
}: {
|
}: {
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
|
let children = _cs;
|
||||||
|
children = create(TranslationProvider, { children }, children);
|
||||||
return create(
|
return create(
|
||||||
BackendProvider,
|
BackendProvider,
|
||||||
{
|
{
|
||||||
|
@ -16,8 +16,9 @@
|
|||||||
|
|
||||||
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
import { TalerErrorDetail } from "@gnu-taler/taler-util";
|
||||||
import { SyncTermsOfServiceResponse } from "@gnu-taler/taler-wallet-core";
|
import { SyncTermsOfServiceResponse } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import {
|
import {
|
||||||
ButtonHandler,
|
ButtonHandler,
|
||||||
TextFieldHandler,
|
TextFieldHandler,
|
||||||
@ -25,11 +26,7 @@ import {
|
|||||||
} from "../../mui/handlers.js";
|
} from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import {
|
import { ConfirmProviderView, SelectProviderView } from "./views.js";
|
||||||
ConfirmProviderView,
|
|
||||||
LoadingUriView,
|
|
||||||
SelectProviderView,
|
|
||||||
} from "./views.js";
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
onBack: () => Promise<void>;
|
onBack: () => Promise<void>;
|
||||||
@ -50,8 +47,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ConfirmProvider {
|
export interface ConfirmProvider {
|
||||||
@ -77,7 +74,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"select-provider": SelectProviderView,
|
"select-provider": SelectProviderView,
|
||||||
"confirm-provider": ConfirmProviderView,
|
"confirm-provider": ConfirmProviderView,
|
||||||
};
|
};
|
||||||
|
@ -17,12 +17,10 @@
|
|||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { Checkbox } from "../../components/Checkbox.js";
|
import { Checkbox } from "../../components/Checkbox.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import {
|
import {
|
||||||
LightText,
|
LightText,
|
||||||
SmallLightText,
|
SmallLightText,
|
||||||
SubTitle,
|
SubTitle,
|
||||||
TermsOfService,
|
|
||||||
Title,
|
Title,
|
||||||
} from "../../components/styled/index.js";
|
} from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
@ -30,17 +28,6 @@ import { Button } from "../../mui/Button.js";
|
|||||||
import { TextField } from "../../mui/TextField.js";
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ConfirmProviderView({
|
export function ConfirmProviderView({
|
||||||
url,
|
url,
|
||||||
provider,
|
provider,
|
||||||
@ -88,9 +75,8 @@ export function ConfirmProviderView({
|
|||||||
of service
|
of service
|
||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
</p>
|
</p>
|
||||||
{/* replace with <TermsOfService /> */}
|
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={<i18n.Translate>Accept terms of service</i18n.Translate>}
|
label={i18n.str`Accept terms of service`}
|
||||||
name="terms"
|
name="terms"
|
||||||
onToggle={tos.button.onClick}
|
onToggle={tos.button.onClick}
|
||||||
enabled={tos.value}
|
enabled={tos.value}
|
||||||
|
@ -25,13 +25,17 @@ import { createHashHistory } from "history";
|
|||||||
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
import { ComponentChildren, Fragment, h, VNode } from "preact";
|
||||||
import Router, { route, Route } from "preact-router";
|
import Router, { route, Route } from "preact-router";
|
||||||
import { useEffect } from "preact/hooks";
|
import { useEffect } from "preact/hooks";
|
||||||
|
import { CurrentAlerts } from "../components/CurrentAlerts.js";
|
||||||
import { LogoHeader } from "../components/LogoHeader.js";
|
import { LogoHeader } from "../components/LogoHeader.js";
|
||||||
import PendingTransactions from "../components/PendingTransactions.js";
|
import PendingTransactions from "../components/PendingTransactions.js";
|
||||||
import {
|
import {
|
||||||
|
Link,
|
||||||
|
LinkPrimary,
|
||||||
SubTitle,
|
SubTitle,
|
||||||
WalletAction,
|
WalletAction,
|
||||||
WalletBox,
|
WalletBox,
|
||||||
} from "../components/styled/index.js";
|
} from "../components/styled/index.js";
|
||||||
|
import { AlertProvider } from "../context/alert.js";
|
||||||
import { DevContextProvider } from "../context/devContext.js";
|
import { DevContextProvider } from "../context/devContext.js";
|
||||||
import { IoCProviderForRuntime } from "../context/iocContext.js";
|
import { IoCProviderForRuntime } from "../context/iocContext.js";
|
||||||
import {
|
import {
|
||||||
@ -66,6 +70,7 @@ import { QrReaderPage } from "./QrReader.js";
|
|||||||
import { SettingsPage } from "./Settings.js";
|
import { SettingsPage } from "./Settings.js";
|
||||||
import { TransactionPage } from "./Transaction.js";
|
import { TransactionPage } from "./Transaction.js";
|
||||||
import { WelcomePage } from "./Welcome.js";
|
import { WelcomePage } from "./Welcome.js";
|
||||||
|
import CloseIcon from "../svg/close_24px.svg";
|
||||||
|
|
||||||
export function Application(): VNode {
|
export function Application(): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
@ -495,15 +500,6 @@ function matchesRoute(url: string, route: string): boolean {
|
|||||||
return !result ? false : true;
|
return !result ? false : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldShowPendingOperations(url: string): boolean {
|
|
||||||
return [
|
|
||||||
Pages.balanceHistory.pattern,
|
|
||||||
Pages.dev,
|
|
||||||
Pages.settings,
|
|
||||||
Pages.backup,
|
|
||||||
].some((p) => matchesRoute(url, p));
|
|
||||||
}
|
|
||||||
|
|
||||||
function CallToActionTemplate({
|
function CallToActionTemplate({
|
||||||
title,
|
title,
|
||||||
children,
|
children,
|
||||||
@ -511,11 +507,35 @@ function CallToActionTemplate({
|
|||||||
title: TranslatedString;
|
title: TranslatedString;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
return (
|
return (
|
||||||
<WalletAction>
|
<WalletAction>
|
||||||
<LogoHeader />
|
<LogoHeader />
|
||||||
|
<section style={{ display: "flex", justifyContent: "right", margin: 0 }}>
|
||||||
|
<LinkPrimary href={Pages.balance}>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
height: 24,
|
||||||
|
width: 24,
|
||||||
|
marginLeft: 4,
|
||||||
|
marginRight: 4,
|
||||||
|
border: "1px solid black",
|
||||||
|
borderRadius: 12,
|
||||||
|
}}
|
||||||
|
dangerouslySetInnerHTML={{ __html: CloseIcon }}
|
||||||
|
/>
|
||||||
|
</LinkPrimary>
|
||||||
|
</section>
|
||||||
<SubTitle>{title}</SubTitle>
|
<SubTitle>{title}</SubTitle>
|
||||||
{children}
|
<AlertProvider>
|
||||||
|
<CurrentAlerts />
|
||||||
|
{children}
|
||||||
|
</AlertProvider>
|
||||||
|
<section style={{ display: "flex", justifyContent: "right" }}>
|
||||||
|
<LinkPrimary href={Pages.balance}>
|
||||||
|
<i18n.Translate>Return to wallet</i18n.Translate>
|
||||||
|
</LinkPrimary>
|
||||||
|
</section>
|
||||||
</WalletAction>
|
</WalletAction>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -536,7 +556,10 @@ function WalletTemplate({
|
|||||||
{goToTransaction ? (
|
{goToTransaction ? (
|
||||||
<PendingTransactions goToTransaction={goToTransaction} />
|
<PendingTransactions goToTransaction={goToTransaction} />
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<WalletBox>{children}</WalletBox>
|
<CurrentAlerts />
|
||||||
|
<WalletBox>
|
||||||
|
<AlertProvider>{children}</AlertProvider>
|
||||||
|
</WalletBox>
|
||||||
</Fragment>
|
</Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@ import {
|
|||||||
} from "date-fns";
|
} from "date-fns";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import { AlertView } from "../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { QR } from "../components/QR.js";
|
import { QR } from "../components/QR.js";
|
||||||
import {
|
import {
|
||||||
BoldLight,
|
BoldLight,
|
||||||
@ -42,6 +42,7 @@ import {
|
|||||||
SmallText,
|
SmallText,
|
||||||
WarningBox,
|
WarningBox,
|
||||||
} from "../components/styled/index.js";
|
} from "../components/styled/index.js";
|
||||||
|
import { alertFromError } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
@ -117,9 +118,11 @@ export function BackupPage({ onAddProvider }: Props): VNode {
|
|||||||
}
|
}
|
||||||
if (status.hasError) {
|
if (status.hasError) {
|
||||||
return (
|
return (
|
||||||
<LoadingError
|
<AlertView
|
||||||
title={<i18n.Translate>Could not load backup providers</i18n.Translate>}
|
alert={alertFromError(
|
||||||
error={status}
|
i18n.str`Could not load backup providers`,
|
||||||
|
status,
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -219,11 +222,9 @@ export function BackupView({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Button variant="contained" onClick={onSyncAll}>
|
<Button variant="contained" onClick={onSyncAll}>
|
||||||
{providers.length > 1 ? (
|
{providers.length > 1
|
||||||
<i18n.Translate>Sync all backups</i18n.Translate>
|
? i18n.str`Sync all backups`
|
||||||
) : (
|
: i18n.str`Sync now`}
|
||||||
<i18n.Translate>Sync now</i18n.Translate>
|
|
||||||
)}
|
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="contained" color="success" onClick={onAddProvider}>
|
<Button variant="contained" color="success" onClick={onAddProvider}>
|
||||||
<i18n.Translate>Add provider</i18n.Translate>
|
<i18n.Translate>Add provider</i18n.Translate>
|
||||||
|
@ -15,8 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
|
import { AmountJson, PaytoUri } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import {
|
import {
|
||||||
AmountFieldHandler,
|
AmountFieldHandler,
|
||||||
ButtonHandler,
|
ButtonHandler,
|
||||||
@ -27,7 +28,6 @@ import { ManageAccountPage } from "../ManageAccount/index.js";
|
|||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import {
|
import {
|
||||||
AmountOrCurrencyErrorView,
|
AmountOrCurrencyErrorView,
|
||||||
LoadingErrorView,
|
|
||||||
NoAccountToDepositView,
|
NoAccountToDepositView,
|
||||||
NoEnoughBalanceView,
|
NoEnoughBalanceView,
|
||||||
ReadyView,
|
ReadyView,
|
||||||
@ -56,8 +56,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AddingAccount {
|
export interface AddingAccount {
|
||||||
@ -107,7 +107,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingErrorView,
|
error: ErrorAlertView,
|
||||||
"amount-or-currency-error": AmountOrCurrencyErrorView,
|
"amount-or-currency-error": AmountOrCurrencyErrorView,
|
||||||
"no-enough-balance": NoEnoughBalanceView,
|
"no-enough-balance": NoEnoughBalanceView,
|
||||||
"no-accounts": NoAccountToDepositView,
|
"no-accounts": NoAccountToDepositView,
|
||||||
|
@ -25,7 +25,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -36,6 +38,7 @@ export function useComponentState({
|
|||||||
onSuccess,
|
onSuccess,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const parsed = amountStr === undefined ? undefined : Amounts.parse(amountStr);
|
const parsed = amountStr === undefined ? undefined : Amounts.parse(amountStr);
|
||||||
const currency = parsed !== undefined ? parsed.currency : currencyStr;
|
const currency = parsed !== undefined ? parsed.currency : currencyStr;
|
||||||
|
|
||||||
@ -82,8 +85,8 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-error",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(i18n.str`Could not load balance information`, hook),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const { accounts, balances } = hook.response;
|
const { accounts, balances } = hook.response;
|
||||||
|
@ -18,31 +18,13 @@ import { Amounts, PaytoUri } from "@gnu-taler/taler-util";
|
|||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { AmountField } from "../../components/AmountField.js";
|
import { AmountField } from "../../components/AmountField.js";
|
||||||
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { SelectList } from "../../components/SelectList.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import {
|
import { Input, SubTitle, WarningBox } from "../../components/styled/index.js";
|
||||||
ErrorText,
|
|
||||||
Input,
|
|
||||||
InputWithLabel,
|
|
||||||
SubTitle,
|
|
||||||
WarningBox,
|
|
||||||
} from "../../components/styled/index.js";
|
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { Grid } from "../../mui/Grid.js";
|
import { Grid } from "../../mui/Grid.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingErrorView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load deposit balance</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function AmountOrCurrencyErrorView(
|
export function AmountOrCurrencyErrorView(
|
||||||
p: State.AmountOrCurrencyError,
|
p: State.AmountOrCurrencyError,
|
||||||
): VNode {
|
): VNode {
|
||||||
@ -50,11 +32,7 @@ export function AmountOrCurrencyErrorView(
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`A currency or an amount should be indicated`}
|
||||||
<i18n.Translate>
|
|
||||||
A currency or an amount should be indicated
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -66,11 +44,7 @@ export function NoEnoughBalanceView({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`There is no enough balance to make a deposit for currency ${currency}`}
|
||||||
<i18n.Translate>
|
|
||||||
There is no enough balance to make a deposit for currency {currency}
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -150,7 +124,7 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
>
|
>
|
||||||
<Input>
|
<Input>
|
||||||
<SelectList
|
<SelectList
|
||||||
label={<i18n.Translate>Select account</i18n.Translate>}
|
label={i18n.str`Select account`}
|
||||||
list={state.account.list}
|
list={state.account.list}
|
||||||
name="account"
|
name="account"
|
||||||
value={state.account.value}
|
value={state.account.value}
|
||||||
@ -171,14 +145,11 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
</p>
|
</p>
|
||||||
<Grid container spacing={2} columns={1}>
|
<Grid container spacing={2} columns={1}>
|
||||||
<Grid item xs={1}>
|
<Grid item xs={1}>
|
||||||
<AmountField
|
<AmountField label={i18n.str`Amount`} handler={state.amount} />
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
|
||||||
handler={state.amount}
|
|
||||||
/>
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={1}>
|
<Grid item xs={1}>
|
||||||
<AmountField
|
<AmountField
|
||||||
label={<i18n.Translate>Deposit fee</i18n.Translate>}
|
label={i18n.str`Deposit fee`}
|
||||||
handler={{
|
handler={{
|
||||||
value: state.totalFee,
|
value: state.totalFee,
|
||||||
}}
|
}}
|
||||||
@ -186,7 +157,7 @@ export function ReadyView(state: State.Ready): VNode {
|
|||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={1}>
|
<Grid item xs={1}>
|
||||||
<AmountField
|
<AmountField
|
||||||
label={<i18n.Translate>Total deposit</i18n.Translate>}
|
label={i18n.str`Total deposit`}
|
||||||
handler={{
|
handler={{
|
||||||
value: state.totalToDeposit,
|
value: state.totalToDeposit,
|
||||||
}}
|
}}
|
||||||
|
@ -14,12 +14,13 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { AmountFieldHandler, ButtonHandler } from "../../mui/handlers.js";
|
import { AmountFieldHandler, ButtonHandler } from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView, SelectCurrencyView } from "./views.js";
|
import { ReadyView, SelectCurrencyView } from "./views.js";
|
||||||
|
|
||||||
export type Props = PropsGet | PropsSend;
|
export type Props = PropsGet | PropsSend;
|
||||||
|
|
||||||
@ -49,8 +50,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectCurrency {
|
export interface SelectCurrency {
|
||||||
@ -80,7 +81,7 @@ export type Contact = {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
"select-currency": SelectCurrencyView,
|
"select-currency": SelectCurrencyView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
@ -17,7 +17,9 @@
|
|||||||
import { Amounts } from "@gnu-taler/taler-util";
|
import { Amounts } from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { assertUnreachable, RecursiveState } from "../../utils/index.js";
|
import { assertUnreachable, RecursiveState } from "../../utils/index.js";
|
||||||
import { Contact, Props, State } from "./index.js";
|
import { Contact, Props, State } from "./index.js";
|
||||||
@ -58,6 +60,8 @@ export function useComponentState(props: Props): RecursiveState<State> {
|
|||||||
|
|
||||||
if (!amount) {
|
if (!amount) {
|
||||||
return () => {
|
return () => {
|
||||||
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
const hook = useAsyncAsHook(() =>
|
const hook = useAsyncAsHook(() =>
|
||||||
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
api.wallet.call(WalletApiOperation.ListExchanges, {}),
|
||||||
@ -71,8 +75,8 @@ export function useComponentState(props: Props): RecursiveState<State> {
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-error",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(i18n.str`Could not load exchanges`, hook),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const currencies: Record<string, string> = {};
|
const currencies: Record<string, string> = {};
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
import { AmountField } from "../../components/AmountField.js";
|
||||||
import { SelectList } from "../../components/SelectList.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
@ -25,24 +25,14 @@ import {
|
|||||||
SvgIcon,
|
SvgIcon,
|
||||||
} from "../../components/styled/index.js";
|
} from "../../components/styled/index.js";
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { Pages } from "../../NavigationBar.js";
|
import { Button } from "../../mui/Button.js";
|
||||||
import { Contact, State } from "./index.js";
|
|
||||||
import arrowIcon from "../../svg/chevron-down.svg";
|
|
||||||
import { AmountField } from "../../components/AmountField.js";
|
|
||||||
import { Grid } from "../../mui/Grid.js";
|
import { Grid } from "../../mui/Grid.js";
|
||||||
import { Paper } from "../../mui/Paper.js";
|
import { Paper } from "../../mui/Paper.js";
|
||||||
import { Button } from "../../mui/Button.js";
|
import { Pages } from "../../NavigationBar.js";
|
||||||
|
import arrowIcon from "../../svg/chevron-down.svg";
|
||||||
|
import bankIcon from "../../svg/ri-bank-line.svg";
|
||||||
import { assertUnreachable } from "../../utils/index.js";
|
import { assertUnreachable } from "../../utils/index.js";
|
||||||
|
import { Contact, State } from "./index.js";
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SelectCurrencyView({
|
export function SelectCurrencyView({
|
||||||
currencies,
|
currencies,
|
||||||
@ -61,7 +51,7 @@ export function SelectCurrencyView({
|
|||||||
<p>
|
<p>
|
||||||
<Input>
|
<Input>
|
||||||
<SelectList
|
<SelectList
|
||||||
label={<i18n.Translate>Known currencies</i18n.Translate>}
|
label={i18n.str`Known currencies`}
|
||||||
list={currencies}
|
list={currencies}
|
||||||
name="lang"
|
name="lang"
|
||||||
value={""}
|
value={""}
|
||||||
@ -214,7 +204,7 @@ export function ReadyGetView({
|
|||||||
</h1>
|
</h1>
|
||||||
<Grid container columns={2} justifyContent="space-between">
|
<Grid container columns={2} justifyContent="space-between">
|
||||||
<AmountField
|
<AmountField
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
label={i18n.str`Amount`}
|
||||||
required
|
required
|
||||||
handler={amountHandler}
|
handler={amountHandler}
|
||||||
/>
|
/>
|
||||||
@ -304,7 +294,7 @@ export function ReadySendView({
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<AmountField
|
<AmountField
|
||||||
label={<i18n.Translate>Amount</i18n.Translate>}
|
label={i18n.str`Amount`}
|
||||||
required
|
required
|
||||||
handler={amountHandler}
|
handler={amountHandler}
|
||||||
/>
|
/>
|
||||||
@ -377,7 +367,6 @@ export function ReadySendView({
|
|||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
import bankIcon from "../../svg/ri-bank-line.svg";
|
|
||||||
|
|
||||||
function RowExample({
|
function RowExample({
|
||||||
info,
|
info,
|
||||||
|
@ -14,11 +14,12 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
p: string;
|
p: string;
|
||||||
@ -33,8 +34,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -48,7 +49,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,21 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { useTranslationContext } from "../../context/translation.js";
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({ error }: State.Ready): VNode {
|
export function ReadyView({ error }: State.Ready): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
|
@ -20,7 +20,9 @@ import {
|
|||||||
ExchangeListItem,
|
ExchangeListItem,
|
||||||
FeeDescriptionPair,
|
FeeDescriptionPair,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
import { State as SelectExchangeState } from "../../hooks/useSelectedExchange.js";
|
||||||
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
import { ButtonHandler, SelectFieldHandler } from "../../mui/handlers.js";
|
||||||
@ -28,7 +30,6 @@ import { compose, StateViewMap } from "../../utils/index.js";
|
|||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import {
|
import {
|
||||||
ComparingView,
|
ComparingView,
|
||||||
ErrorLoadingView,
|
|
||||||
NoExchangesView,
|
NoExchangesView,
|
||||||
PrivacyContentView,
|
PrivacyContentView,
|
||||||
ReadyView,
|
ReadyView,
|
||||||
@ -58,8 +59,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "error-loading";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -99,7 +100,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"error-loading": ErrorLoadingView,
|
error: ErrorAlertView,
|
||||||
comparing: ComparingView,
|
comparing: ComparingView,
|
||||||
"no-exchange": NoExchangesView,
|
"no-exchange": NoExchangesView,
|
||||||
"showing-tos": TosContentView,
|
"showing-tos": TosContentView,
|
||||||
|
@ -20,7 +20,9 @@ import {
|
|||||||
WalletApiOperation,
|
WalletApiOperation,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ export function useComponentState({
|
|||||||
currentExchange,
|
currentExchange,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const initialValue = exchanges.findIndex(
|
const initialValue = exchanges.findIndex(
|
||||||
(e) => e.exchangeBaseUrl === currentExchange,
|
(e) => e.exchangeBaseUrl === currentExchange,
|
||||||
);
|
);
|
||||||
@ -84,8 +87,11 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "error-loading",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load exchange details info`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ import { Fragment, h, VNode } from "preact";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { Amount } from "../../components/Amount.js";
|
import { Amount } from "../../components/Amount.js";
|
||||||
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import { SelectList } from "../../components/SelectList.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import { Input, SvgIcon } from "../../components/styled/index.js";
|
import { Input, SvgIcon } from "../../components/styled/index.js";
|
||||||
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
import { TermsOfService } from "../../components/TermsOfService/index.js";
|
||||||
@ -110,17 +109,6 @@ const Container = styled.div`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function ErrorLoadingView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load exchange fees</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function PrivacyContentView({
|
export function PrivacyContentView({
|
||||||
exchangeUrl,
|
exchangeUrl,
|
||||||
onClose,
|
onClose,
|
||||||
@ -156,19 +144,11 @@ export function NoExchangesView({
|
|||||||
}: SelectExchangeState.NoExchange): VNode {
|
}: SelectExchangeState.NoExchange): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
if (!currency) {
|
if (!currency) {
|
||||||
return (
|
return <ErrorMessage title={i18n.str`Could not find any exchange`} />;
|
||||||
<ErrorMessage
|
|
||||||
title={<i18n.Translate>Could not find any exchange</i18n.Translate>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`Could not find any exchange for the currency ${currency}`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not find any exchange for the currency {currency}
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -140,15 +140,13 @@ export function ExchangeSetUrlPage({
|
|||||||
)}
|
)}
|
||||||
{error && (
|
{error && (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`Unable to verify this exchange`}
|
||||||
<i18n.Translate>Unable to verify this exchange</i18n.Translate>
|
|
||||||
}
|
|
||||||
description={error}
|
description={error}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{confirmationError && (
|
{confirmationError && (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={<i18n.Translate>Unable to add this exchange</i18n.Translate>}
|
title={i18n.str`Unable to add this exchange`}
|
||||||
description={confirmationError}
|
description={confirmationError}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
@ -23,8 +23,8 @@ import {
|
|||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
import { AlertView } from "../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import {
|
import {
|
||||||
CenteredBoldText,
|
CenteredBoldText,
|
||||||
CenteredText,
|
CenteredText,
|
||||||
@ -33,6 +33,7 @@ import {
|
|||||||
} from "../components/styled/index.js";
|
} from "../components/styled/index.js";
|
||||||
import { Time } from "../components/Time.js";
|
import { Time } from "../components/Time.js";
|
||||||
import { TransactionItem } from "../components/TransactionItem.js";
|
import { TransactionItem } from "../components/TransactionItem.js";
|
||||||
|
import { alertFromError } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
@ -71,13 +72,11 @@ export function HistoryPage({
|
|||||||
|
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return (
|
||||||
<LoadingError
|
<AlertView
|
||||||
title={
|
alert={alertFromError(
|
||||||
<i18n.Translate>
|
i18n.str`Could not load the list of transactions`,
|
||||||
Could not load the list of transactions
|
state,
|
||||||
</i18n.Translate>
|
)}
|
||||||
}
|
|
||||||
error={state}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { KnownBankAccountsInfo } from "@gnu-taler/taler-util";
|
import { KnownBankAccountsInfo } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import {
|
import {
|
||||||
ButtonHandler,
|
ButtonHandler,
|
||||||
SelectFieldHandler,
|
SelectFieldHandler,
|
||||||
@ -24,7 +25,7 @@ import {
|
|||||||
} from "../../mui/handlers.js";
|
} from "../../mui/handlers.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
currency: string;
|
currency: string;
|
||||||
@ -41,8 +42,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -68,7 +69,7 @@ export type AccountByType = {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,9 @@ import {
|
|||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { AccountByType, Props, State } from "./index.js";
|
import { AccountByType, Props, State } from "./index.js";
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ export function useComponentState({
|
|||||||
onCancel,
|
onCancel,
|
||||||
}: Props): State {
|
}: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const hook = useAsyncAsHook(() =>
|
const hook = useAsyncAsHook(() =>
|
||||||
api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }),
|
api.wallet.call(WalletApiOperation.ListKnownBankAccounts, { currency }),
|
||||||
);
|
);
|
||||||
@ -47,8 +50,8 @@ export function useComponentState({
|
|||||||
}
|
}
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-error",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(i18n.str`Could not load known bank accounts`, hook),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,11 +23,10 @@ import {
|
|||||||
import { styled } from "@linaria/react";
|
import { styled } from "@linaria/react";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
||||||
import { SelectList } from "../../components/SelectList.js";
|
import { SelectList } from "../../components/SelectList.js";
|
||||||
import {
|
import {
|
||||||
Input,
|
Input,
|
||||||
LightText,
|
|
||||||
SubTitle,
|
SubTitle,
|
||||||
SvgIcon,
|
SvgIcon,
|
||||||
WarningText,
|
WarningText,
|
||||||
@ -37,10 +36,9 @@ import { Button } from "../../mui/Button.js";
|
|||||||
import { TextFieldHandler } from "../../mui/handlers.js";
|
import { TextFieldHandler } from "../../mui/handlers.js";
|
||||||
import { TextField } from "../../mui/TextField.js";
|
import { TextField } from "../../mui/TextField.js";
|
||||||
import checkIcon from "../../svg/check_24px.svg";
|
import checkIcon from "../../svg/check_24px.svg";
|
||||||
import warningIcon from "../../svg/warning_24px.svg";
|
|
||||||
import deleteIcon from "../../svg/delete_24px.svg";
|
import deleteIcon from "../../svg/delete_24px.svg";
|
||||||
|
import warningIcon from "../../svg/warning_24px.svg";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
import { ErrorMessage } from "../../components/ErrorMessage.js";
|
|
||||||
|
|
||||||
type AccountType = "bitcoin" | "x-taler-bank" | "iban";
|
type AccountType = "bitcoin" | "x-taler-bank" | "iban";
|
||||||
type ComponentFormByAccountType = {
|
type ComponentFormByAccountType = {
|
||||||
@ -80,17 +78,6 @@ const AccountTable = styled.table`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ReadyView({
|
export function ReadyView({
|
||||||
currency,
|
currency,
|
||||||
error,
|
error,
|
||||||
@ -118,14 +105,14 @@ export function ReadyView({
|
|||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={<i18n.Translate>Unable add this account</i18n.Translate>}
|
title={i18n.str`Unable add this account`}
|
||||||
description={error}
|
description={error}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<p>
|
<p>
|
||||||
<Input>
|
<Input>
|
||||||
<SelectList
|
<SelectList
|
||||||
label={<i18n.Translate>Select account type</i18n.Translate>}
|
label={i18n.str`Select account type`}
|
||||||
list={accountType.list}
|
list={accountType.list}
|
||||||
name="accountType"
|
name="accountType"
|
||||||
value={accountType.value}
|
value={accountType.value}
|
||||||
|
@ -15,11 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { UserAttentionUnreadList } from "@gnu-taler/taler-util";
|
import { UserAttentionUnreadList } from "@gnu-taler/taler-util";
|
||||||
|
import { ErrorAlertView } from "../../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../../components/Loading.js";
|
import { Loading } from "../../components/Loading.js";
|
||||||
import { HookError } from "../../hooks/useAsyncAsHook.js";
|
import { ErrorAlert } from "../../context/alert.js";
|
||||||
import { compose, StateViewMap } from "../../utils/index.js";
|
import { compose, StateViewMap } from "../../utils/index.js";
|
||||||
import { useComponentState } from "./state.js";
|
import { useComponentState } from "./state.js";
|
||||||
import { LoadingUriView, ReadyView } from "./views.js";
|
import { ReadyView } from "./views.js";
|
||||||
|
|
||||||
export type Props = object;
|
export type Props = object;
|
||||||
|
|
||||||
@ -32,8 +33,8 @@ export namespace State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadingUriError {
|
export interface LoadingUriError {
|
||||||
status: "loading-error";
|
status: "error";
|
||||||
error: HookError;
|
error: ErrorAlert;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BaseInfo {
|
export interface BaseInfo {
|
||||||
@ -49,7 +50,7 @@ export namespace State {
|
|||||||
|
|
||||||
const viewMapping: StateViewMap<State> = {
|
const viewMapping: StateViewMap<State> = {
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
"loading-error": LoadingUriView,
|
error: ErrorAlertView,
|
||||||
ready: ReadyView,
|
ready: ReadyView,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,12 +15,15 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
|
import { alertFromError } from "../../context/alert.js";
|
||||||
import { useBackendContext } from "../../context/backend.js";
|
import { useBackendContext } from "../../context/backend.js";
|
||||||
|
import { useTranslationContext } from "../../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../../hooks/useAsyncAsHook.js";
|
||||||
import { Props, State } from "./index.js";
|
import { Props, State } from "./index.js";
|
||||||
|
|
||||||
export function useComponentState(p: Props): State {
|
export function useComponentState(p: Props): State {
|
||||||
const api = useBackendContext();
|
const api = useBackendContext();
|
||||||
|
const { i18n } = useTranslationContext();
|
||||||
const hook = useAsyncAsHook(async () => {
|
const hook = useAsyncAsHook(async () => {
|
||||||
return await api.wallet.call(
|
return await api.wallet.call(
|
||||||
WalletApiOperation.GetUserAttentionRequests,
|
WalletApiOperation.GetUserAttentionRequests,
|
||||||
@ -34,10 +37,14 @@ export function useComponentState(p: Props): State {
|
|||||||
error: undefined,
|
error: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hook.hasError) {
|
if (hook.hasError) {
|
||||||
return {
|
return {
|
||||||
status: "loading-error",
|
status: "error",
|
||||||
error: hook,
|
error: alertFromError(
|
||||||
|
i18n.str`Could not load user attention request`,
|
||||||
|
hook,
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ import {
|
|||||||
AttentionType,
|
AttentionType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
import { LoadingError } from "../../components/LoadingError.js";
|
|
||||||
import {
|
import {
|
||||||
Column,
|
Column,
|
||||||
DateSeparator,
|
DateSeparator,
|
||||||
@ -37,17 +36,6 @@ import { Pages } from "../../NavigationBar.js";
|
|||||||
import { assertUnreachable } from "../../utils/index.js";
|
import { assertUnreachable } from "../../utils/index.js";
|
||||||
import { State } from "./index.js";
|
import { State } from "./index.js";
|
||||||
|
|
||||||
export function LoadingUriView({ error }: State.LoadingUriError): VNode {
|
|
||||||
const { i18n } = useTranslationContext();
|
|
||||||
|
|
||||||
return (
|
|
||||||
<LoadingError
|
|
||||||
title={<i18n.Translate>Could not load notifications</i18n.Translate>}
|
|
||||||
error={error}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const term = 1000 * 60 * 60 * 24;
|
const term = 1000 * 60 * 60 * 24;
|
||||||
function normalizeToDay(x: number): number {
|
function normalizeToDay(x: number): number {
|
||||||
return Math.round(x / term) * term;
|
return Math.round(x / term) * term;
|
||||||
|
@ -127,11 +127,7 @@ export function SetUrlView({
|
|||||||
</Title>
|
</Title>
|
||||||
{error && (
|
{error && (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`Could not get provider information`}
|
||||||
<i18n.Translate>
|
|
||||||
Could not get provider information
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
description={error}
|
description={error}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -223,7 +219,7 @@ export function ConfirmProviderView({
|
|||||||
</SubTitle>
|
</SubTitle>
|
||||||
<p>
|
<p>
|
||||||
{Amounts.isZero(provider.annual_fee) ? (
|
{Amounts.isZero(provider.annual_fee) ? (
|
||||||
<i18n.Translate>free of charge</i18n.Translate>
|
i18n.str`free of charge`
|
||||||
) : (
|
) : (
|
||||||
<i18n.Translate>
|
<i18n.Translate>
|
||||||
{provider.annual_fee} per year of service
|
{provider.annual_fee} per year of service
|
||||||
@ -240,7 +236,7 @@ export function ConfirmProviderView({
|
|||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
</p>
|
</p>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={<i18n.Translate>Accept terms of service</i18n.Translate>}
|
label={i18n.str`Accept terms of service`}
|
||||||
name="terms"
|
name="terms"
|
||||||
onToggle={async () => setAccepted((old) => !old)}
|
onToggle={async () => setAccepted((old) => !old)}
|
||||||
enabled={accepted}
|
enabled={accepted}
|
||||||
|
@ -23,11 +23,12 @@ import {
|
|||||||
WalletApiOperation,
|
WalletApiOperation,
|
||||||
} from "@gnu-taler/taler-wallet-core";
|
} from "@gnu-taler/taler-wallet-core";
|
||||||
import { Fragment, h, VNode } from "preact";
|
import { Fragment, h, VNode } from "preact";
|
||||||
|
import { AlertView } from "../components/CurrentAlerts.js";
|
||||||
import { ErrorMessage } from "../components/ErrorMessage.js";
|
import { ErrorMessage } from "../components/ErrorMessage.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { PaymentStatus, SmallLightText } from "../components/styled/index.js";
|
import { PaymentStatus, SmallLightText } from "../components/styled/index.js";
|
||||||
import { Time } from "../components/Time.js";
|
import { Time } from "../components/Time.js";
|
||||||
|
import { alertFromError } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
@ -65,14 +66,11 @@ export function ProviderDetailPage({
|
|||||||
}
|
}
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return (
|
||||||
<LoadingError
|
<AlertView
|
||||||
title={
|
alert={alertFromError(
|
||||||
<i18n.Translate>
|
i18n.str`There was an error loading the provider detail for "${providerURL}"`,
|
||||||
There was an error loading the provider detail for "
|
state,
|
||||||
{providerURL}"
|
)}
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
error={state}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -270,9 +268,7 @@ function Error({ info }: { info: ProviderInfo }): VNode {
|
|||||||
if (info.lastError) {
|
if (info.lastError) {
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`This provider has reported an error`}
|
||||||
<i18n.Translate>This provider has reported an error</i18n.Translate>
|
|
||||||
}
|
|
||||||
description={info.lastError.hint}
|
description={info.lastError.hint}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -282,32 +278,17 @@ function Error({ info }: { info: ProviderInfo }): VNode {
|
|||||||
case "backup-conflicting-device":
|
case "backup-conflicting-device":
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`There is conflict with another backup from "${info.backupProblem.otherDeviceId}"`}
|
||||||
<Fragment>
|
|
||||||
<i18n.Translate>
|
|
||||||
There is conflict with another backup from{" "}
|
|
||||||
<b>{info.backupProblem.otherDeviceId}</b>
|
|
||||||
</i18n.Translate>
|
|
||||||
</Fragment>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "backup-unreadable":
|
case "backup-unreadable":
|
||||||
return (
|
return <ErrorMessage title={i18n.str`Backup is not readable`} />;
|
||||||
<ErrorMessage
|
|
||||||
title={<i18n.Translate>Backup is not readable</i18n.Translate>}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={
|
title={i18n.str`Unknown backup problem: ${JSON.stringify(
|
||||||
<Fragment>
|
info.backupProblem,
|
||||||
<i18n.Translate>
|
)}`}
|
||||||
Unknown backup problem: {JSON.stringify(info.backupProblem)}
|
|
||||||
</i18n.Translate>
|
|
||||||
</Fragment>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -42,8 +42,8 @@ export function ReserveCreated({
|
|||||||
if (!paytoURI) {
|
if (!paytoURI) {
|
||||||
return (
|
return (
|
||||||
<ErrorMessage
|
<ErrorMessage
|
||||||
title={<i18n.Translate>Could not parse the payto URI</i18n.Translate>}
|
title={i18n.str`Could not parse the payto URI`}
|
||||||
description={<i18n.Translate>Please check the uri</i18n.Translate>}
|
description={i18n.str`Please check the uri`}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -111,13 +111,13 @@ export function SettingsView({
|
|||||||
<section>
|
<section>
|
||||||
{autoOpenToggle.button.error && (
|
{autoOpenToggle.button.error && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={<i18n.Translate>Could not toggle auto-open</i18n.Translate>}
|
title={i18n.str`Could not toggle auto-open`}
|
||||||
error={autoOpenToggle.button.error.errorDetail}
|
error={autoOpenToggle.button.error.errorDetail}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* {clipboardToggle.button.error && (
|
{/* {clipboardToggle.button.error && (
|
||||||
<ErrorTalerOperation
|
<ErrorTalerOperation
|
||||||
title={<i18n.Translate>Could not toggle clipboard</i18n.Translate>}
|
title={i18n.str`Could not toggle clipboard`}
|
||||||
error={clipboardToggle.button.error.errorDetail}
|
error={clipboardToggle.button.error.errorDetail}
|
||||||
/>
|
/>
|
||||||
)} */}
|
)} */}
|
||||||
@ -125,11 +125,7 @@ export function SettingsView({
|
|||||||
<i18n.Translate>Navigator</i18n.Translate>
|
<i18n.Translate>Navigator</i18n.Translate>
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={
|
label={i18n.str`Automatically open wallet based on page content`}
|
||||||
<i18n.Translate>
|
|
||||||
Automatically open wallet based on page content
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
name="autoOpen"
|
name="autoOpen"
|
||||||
description={
|
description={
|
||||||
<i18n.Translate>
|
<i18n.Translate>
|
||||||
@ -142,9 +138,7 @@ export function SettingsView({
|
|||||||
/>
|
/>
|
||||||
{/* <Checkbox
|
{/* <Checkbox
|
||||||
label={
|
label={
|
||||||
<i18n.Translate>
|
i18n.str`Automatically check clipboard for Taler URI`
|
||||||
Automatically check clipboard for Taler URI
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
}
|
||||||
name="clipboard"
|
name="clipboard"
|
||||||
description={
|
description={
|
||||||
@ -241,13 +235,9 @@ export function SettingsView({
|
|||||||
<i18n.Translate>Troubleshooting</i18n.Translate>
|
<i18n.Translate>Troubleshooting</i18n.Translate>
|
||||||
</SubTitle>
|
</SubTitle>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label={<i18n.Translate>Developer mode</i18n.Translate>}
|
label={i18n.str`Developer mode`}
|
||||||
name="devMode"
|
name="devMode"
|
||||||
description={
|
description={i18n.str`More options and information useful for debugging`}
|
||||||
<i18n.Translate>
|
|
||||||
More options and information useful for debugging
|
|
||||||
</i18n.Translate>
|
|
||||||
}
|
|
||||||
enabled={devModeToggle.value!}
|
enabled={devModeToggle.value!}
|
||||||
onToggle={devModeToggle.button.onClick!}
|
onToggle={devModeToggle.button.onClick!}
|
||||||
/>
|
/>
|
||||||
@ -271,7 +261,7 @@ export function SettingsView({
|
|||||||
</SubTitle>
|
</SubTitle>
|
||||||
{coreVersion && (
|
{coreVersion && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Wallet Core</i18n.Translate>}
|
title={i18n.str`Wallet Core`}
|
||||||
text={
|
text={
|
||||||
<span>
|
<span>
|
||||||
{coreVersion.version}{" "}
|
{coreVersion.version}{" "}
|
||||||
@ -281,7 +271,7 @@ export function SettingsView({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Web Extension</i18n.Translate>}
|
title={i18n.str`Web Extension`}
|
||||||
text={
|
text={
|
||||||
<span>
|
<span>
|
||||||
{webexVersion.version}{" "}
|
{webexVersion.version}{" "}
|
||||||
@ -292,15 +282,15 @@ export function SettingsView({
|
|||||||
{coreVersion && (
|
{coreVersion && (
|
||||||
<JustInDevMode>
|
<JustInDevMode>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange compatibility</i18n.Translate>}
|
title={i18n.str`Exchange compatibility`}
|
||||||
text={<span>{coreVersion.exchange}</span>}
|
text={<span>{coreVersion.exchange}</span>}
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant compatibility</i18n.Translate>}
|
title={i18n.str`Merchant compatibility`}
|
||||||
text={<span>{coreVersion.merchant}</span>}
|
text={<span>{coreVersion.merchant}</span>}
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Bank compatibility</i18n.Translate>}
|
title={i18n.str`Bank compatibility`}
|
||||||
text={<span>{coreVersion.bank}</span>}
|
text={<span>{coreVersion.bank}</span>}
|
||||||
/>
|
/>
|
||||||
</JustInDevMode>
|
</JustInDevMode>
|
||||||
|
@ -32,6 +32,7 @@ import {
|
|||||||
TransactionRefund,
|
TransactionRefund,
|
||||||
TransactionTip,
|
TransactionTip,
|
||||||
TransactionType,
|
TransactionType,
|
||||||
|
TranslatedString,
|
||||||
WithdrawalType,
|
WithdrawalType,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
import { WalletApiOperation } from "@gnu-taler/taler-wallet-core";
|
||||||
@ -43,9 +44,8 @@ import emptyImg from "../../static/img/empty.png";
|
|||||||
import { Amount } from "../components/Amount.js";
|
import { Amount } from "../components/Amount.js";
|
||||||
import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js";
|
import { BankDetailsByPaytoType } from "../components/BankDetailsByPaytoType.js";
|
||||||
import { CopyButton } from "../components/CopyButton.js";
|
import { CopyButton } from "../components/CopyButton.js";
|
||||||
import { ErrorTalerOperation } from "../components/ErrorTalerOperation.js";
|
import { AlertView, ErrorAlertView } from "../components/CurrentAlerts.js";
|
||||||
import { Loading } from "../components/Loading.js";
|
import { Loading } from "../components/Loading.js";
|
||||||
import { LoadingError } from "../components/LoadingError.js";
|
|
||||||
import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js";
|
import { Kind, Part, PartCollapsible, PartPayto } from "../components/Part.js";
|
||||||
import { QR } from "../components/QR.js";
|
import { QR } from "../components/QR.js";
|
||||||
import { ShowFullContractTermPopup } from "../components/ShowFullContractTermPopup.js";
|
import { ShowFullContractTermPopup } from "../components/ShowFullContractTermPopup.js";
|
||||||
@ -60,6 +60,7 @@ import {
|
|||||||
WarningBox,
|
WarningBox,
|
||||||
} from "../components/styled/index.js";
|
} from "../components/styled/index.js";
|
||||||
import { Time } from "../components/Time.js";
|
import { Time } from "../components/Time.js";
|
||||||
|
import { alertFromError } from "../context/alert.js";
|
||||||
import { useBackendContext } from "../context/backend.js";
|
import { useBackendContext } from "../context/backend.js";
|
||||||
import { useTranslationContext } from "../context/translation.js";
|
import { useTranslationContext } from "../context/translation.js";
|
||||||
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
import { useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
|
||||||
@ -98,13 +99,11 @@ export function TransactionPage({
|
|||||||
|
|
||||||
if (state.hasError) {
|
if (state.hasError) {
|
||||||
return (
|
return (
|
||||||
<LoadingError
|
<AlertView
|
||||||
title={
|
alert={alertFromError(
|
||||||
<i18n.Translate>
|
i18n.str`Could not load transaction information`,
|
||||||
Could not load the transaction information
|
state,
|
||||||
</i18n.Translate>
|
)}
|
||||||
}
|
|
||||||
error={state}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -199,14 +198,14 @@ export function TransactionView({
|
|||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
<section style={{ padding: 8, textAlign: "center" }}>
|
<section style={{ padding: 8, textAlign: "center" }}>
|
||||||
<ErrorTalerOperation
|
{transaction?.error ? (
|
||||||
title={
|
<ErrorAlertView
|
||||||
<i18n.Translate>
|
error={alertFromError(
|
||||||
There was an error trying to complete the transaction
|
i18n.str`There was an error trying to complete the transaction`,
|
||||||
</i18n.Translate>
|
transaction.error,
|
||||||
}
|
)}
|
||||||
error={transaction?.error}
|
/>
|
||||||
/>
|
) : undefined}
|
||||||
{transaction.pending && (
|
{transaction.pending && (
|
||||||
<WarningBox>
|
<WarningBox>
|
||||||
<i18n.Translate>This transaction is not completed</i18n.Translate>
|
<i18n.Translate>This transaction is not completed</i18n.Translate>
|
||||||
@ -367,7 +366,7 @@ export function TransactionView({
|
|||||||
</Fragment>
|
</Fragment>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<WithdrawDetails
|
<WithdrawDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -420,7 +419,7 @@ export function TransactionView({
|
|||||||
<br />
|
<br />
|
||||||
{transaction.refunds.length > 0 ? (
|
{transaction.refunds.length > 0 ? (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Refunds</i18n.Translate>}
|
title={i18n.str`Refunds`}
|
||||||
text={
|
text={
|
||||||
<table>
|
<table>
|
||||||
{transaction.refunds.map((r, i) => {
|
{transaction.refunds.map((r, i) => {
|
||||||
@ -462,7 +461,7 @@ export function TransactionView({
|
|||||||
picked up.
|
picked up.
|
||||||
</i18n.Translate>
|
</i18n.Translate>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Offer</i18n.Translate>}
|
title={i18n.str`Offer`}
|
||||||
text={<Amount value={pendingRefund} />}
|
text={<Amount value={pendingRefund} />}
|
||||||
kind="positive"
|
kind="positive"
|
||||||
/>
|
/>
|
||||||
@ -480,17 +479,17 @@ export function TransactionView({
|
|||||||
</InfoBox>
|
</InfoBox>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant</i18n.Translate>}
|
title={i18n.str`Merchant`}
|
||||||
text={<MerchantDetails merchant={transaction.info.merchant} />}
|
text={<MerchantDetails merchant={transaction.info.merchant} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Invoice ID</i18n.Translate>}
|
title={i18n.str`Invoice ID`}
|
||||||
text={transaction.info.orderId}
|
text={transaction.info.orderId as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<PurchaseDetails
|
<PurchaseDetails
|
||||||
price={price}
|
price={price}
|
||||||
@ -520,12 +519,12 @@ export function TransactionView({
|
|||||||
</Header>
|
</Header>
|
||||||
{payto && <PartPayto payto={payto} kind="neutral" />}
|
{payto && <PartPayto payto={payto} kind="neutral" />}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={<DepositDetails transaction={transaction} />}
|
text={<DepositDetails transaction={transaction} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Wire transfer deadline</i18n.Translate>}
|
title={i18n.str`Wire transfer deadline`}
|
||||||
text={
|
text={
|
||||||
<Time
|
<Time
|
||||||
timestamp={AbsoluteTime.fromTimestamp(
|
timestamp={AbsoluteTime.fromTimestamp(
|
||||||
@ -557,7 +556,7 @@ export function TransactionView({
|
|||||||
{transaction.exchangeBaseUrl}
|
{transaction.exchangeBaseUrl}
|
||||||
</Header>
|
</Header>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={<RefreshDetails transaction={transaction} />}
|
text={<RefreshDetails transaction={transaction} />}
|
||||||
/>
|
/>
|
||||||
</TransactionTemplate>
|
</TransactionTemplate>
|
||||||
@ -578,12 +577,12 @@ export function TransactionView({
|
|||||||
{transaction.merchantBaseUrl}
|
{transaction.merchantBaseUrl}
|
||||||
</Header>
|
</Header>
|
||||||
{/* <Part
|
{/* <Part
|
||||||
title={<i18n.Translate>Merchant</i18n.Translate>}
|
title={i18n.str`Merchant`}
|
||||||
text={<MerchantDetails merchant={transaction.merchant} />}
|
text={<MerchantDetails merchant={transaction.merchant} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/> */}
|
/> */}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={<TipDetails transaction={transaction} />}
|
text={<TipDetails transaction={transaction} />}
|
||||||
/>
|
/>
|
||||||
</TransactionTemplate>
|
</TransactionTemplate>
|
||||||
@ -604,12 +603,12 @@ export function TransactionView({
|
|||||||
</Header>
|
</Header>
|
||||||
|
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Merchant</i18n.Translate>}
|
title={i18n.str`Merchant`}
|
||||||
text={transaction.info.merchant.name}
|
text={transaction.info.merchant.name as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Original order ID</i18n.Translate>}
|
title={i18n.str`Original order ID`}
|
||||||
text={
|
text={
|
||||||
<a
|
<a
|
||||||
href={Pages.balanceTransaction({
|
href={Pages.balanceTransaction({
|
||||||
@ -622,12 +621,12 @@ export function TransactionView({
|
|||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Purchase summary</i18n.Translate>}
|
title={i18n.str`Purchase summary`}
|
||||||
text={transaction.info.summary}
|
text={transaction.info.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={<RefundDetails transaction={transaction} />}
|
text={<RefundDetails transaction={transaction} />}
|
||||||
/>
|
/>
|
||||||
</TransactionTemplate>
|
</TransactionTemplate>
|
||||||
@ -683,25 +682,25 @@ export function TransactionView({
|
|||||||
|
|
||||||
{transaction.info.summary ? (
|
{transaction.info.summary ? (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Subject`}
|
||||||
text={transaction.info.summary}
|
text={transaction.info.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange</i18n.Translate>}
|
title={i18n.str`Exchange`}
|
||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
{transaction.pending /** pending is not-pay */ && (
|
{transaction.pending /** pending is not-pay */ && (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>URI</i18n.Translate>}
|
title={i18n.str`URI`}
|
||||||
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<InvoiceDetails
|
<InvoiceDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -730,18 +729,18 @@ export function TransactionView({
|
|||||||
|
|
||||||
{transaction.info.summary ? (
|
{transaction.info.summary ? (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Subject`}
|
||||||
text={transaction.info.summary}
|
text={transaction.info.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange</i18n.Translate>}
|
title={i18n.str`Exchange`}
|
||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<InvoiceDetails
|
<InvoiceDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -769,25 +768,25 @@ export function TransactionView({
|
|||||||
|
|
||||||
{transaction.info.summary ? (
|
{transaction.info.summary ? (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Subject`}
|
||||||
text={transaction.info.summary}
|
text={transaction.info.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange</i18n.Translate>}
|
title={i18n.str`Exchange`}
|
||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
{/* {transaction.pending && ( //pending is not-received
|
{/* {transaction.pending && ( //pending is not-received
|
||||||
)} */}
|
)} */}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>URI</i18n.Translate>}
|
title={i18n.str`URI`}
|
||||||
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
text={<ShowQrWithCopy text={transaction.talerUri} />}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<TransferDetails
|
<TransferDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -816,18 +815,18 @@ export function TransactionView({
|
|||||||
|
|
||||||
{transaction.info.summary ? (
|
{transaction.info.summary ? (
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Subject</i18n.Translate>}
|
title={i18n.str`Subject`}
|
||||||
text={transaction.info.summary}
|
text={transaction.info.summary as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Exchange</i18n.Translate>}
|
title={i18n.str`Exchange`}
|
||||||
text={transaction.exchangeBaseUrl}
|
text={transaction.exchangeBaseUrl as TranslatedString}
|
||||||
kind="neutral"
|
kind="neutral"
|
||||||
/>
|
/>
|
||||||
<Part
|
<Part
|
||||||
title={<i18n.Translate>Details</i18n.Translate>}
|
title={i18n.str`Details`}
|
||||||
text={
|
text={
|
||||||
<TransferDetails
|
<TransferDetails
|
||||||
amount={{
|
amount={{
|
||||||
@ -1245,7 +1244,7 @@ export function PurchaseDetails({
|
|||||||
<td colSpan={2}>
|
<td colSpan={2}>
|
||||||
<PartCollapsible
|
<PartCollapsible
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Products</i18n.Translate>}
|
title={i18n.str`Products`}
|
||||||
text={
|
text={
|
||||||
<ListOfProducts>
|
<ListOfProducts>
|
||||||
{info.products?.map((p, k) => (
|
{info.products?.map((p, k) => (
|
||||||
@ -1274,7 +1273,7 @@ export function PurchaseDetails({
|
|||||||
<td colSpan={2}>
|
<td colSpan={2}>
|
||||||
<PartCollapsible
|
<PartCollapsible
|
||||||
big
|
big
|
||||||
title={<i18n.Translate>Delivery</i18n.Translate>}
|
title={i18n.str`Delivery`}
|
||||||
text={
|
text={
|
||||||
<DeliveryDetails
|
<DeliveryDetails
|
||||||
date={info.delivery_date}
|
date={info.delivery_date}
|
||||||
@ -1508,7 +1507,7 @@ function Header({
|
|||||||
total: AmountJson;
|
total: AmountJson;
|
||||||
children: ComponentChildren;
|
children: ComponentChildren;
|
||||||
kind: Kind;
|
kind: Kind;
|
||||||
type: string;
|
type: TranslatedString;
|
||||||
}): VNode {
|
}): VNode {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user