aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/components
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-08-08 14:09:28 -0300
committerSebastian <sebasjm@gmail.com>2022-08-08 14:09:36 -0300
commit7a600514c6d43bbaeba6b962533415e59fc46057 (patch)
treed96c02537cda29f1637787a8fb8e659a37ea8c1f /packages/taler-wallet-webextension/src/components
parent4409d8384b77401489c2a92d3de20f79959ae34a (diff)
downloadwallet-core-7a600514c6d43bbaeba6b962533415e59fc46057.tar.xz
fixing #6096
merchant details and contract terms details factored out, to be used by other components tests and stories updated payment completed != confirmed (confirmed if paid by someone else)
Diffstat (limited to 'packages/taler-wallet-webextension/src/components')
-rw-r--r--packages/taler-wallet-webextension/src/components/Modal.tsx91
-rw-r--r--packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx116
-rw-r--r--packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx385
-rw-r--r--packages/taler-wallet-webextension/src/components/index.stories.tsx5
-rw-r--r--packages/taler-wallet-webextension/src/components/styled/index.tsx10
5 files changed, 605 insertions, 2 deletions
diff --git a/packages/taler-wallet-webextension/src/components/Modal.tsx b/packages/taler-wallet-webextension/src/components/Modal.tsx
new file mode 100644
index 000000000..3fea063d3
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/Modal.tsx
@@ -0,0 +1,91 @@
+/*
+ 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 { styled } from "@linaria/react";
+import { ComponentChildren, h, VNode } from "preact";
+import { ButtonHandler } from "../mui/handlers.js";
+import closeIcon from "../svg/close_24px.svg";
+import { Link, LinkPrimary, LinkWarning } from "./styled/index.js";
+
+interface Props {
+ children: ComponentChildren;
+ onClose: ButtonHandler;
+ title: string;
+}
+
+const FullSize = styled.div`
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: flex;
+ justify-content: center;
+ z-index: 10;
+`;
+
+const Header = styled.div`
+ display: flex;
+ justify-content: space-between;
+ height: 5%;
+ vertical-align: center;
+ align-items: center;
+`;
+
+const Body = styled.div`
+ height: 95%;
+`;
+
+export function Modal({ title, children, onClose }: Props): VNode {
+ return (
+ <FullSize onClick={onClose?.onClick}>
+ <div
+ onClick={(e) => e.stopPropagation()}
+ style={{
+ background: "white",
+ width: 600,
+ height: "80%",
+ margin: "auto",
+ borderRadius: 8,
+ padding: 8,
+ // overflow: "scroll",
+ }}
+ >
+ <Header>
+ <div>
+ <h2>{title}</h2>
+ </div>
+ <Link onClick={onClose?.onClick}>
+ <div
+ style={{
+ height: 24,
+ width: 24,
+ marginLeft: 4,
+ marginRight: 4,
+ // fill: "white",
+ }}
+ dangerouslySetInnerHTML={{ __html: closeIcon }}
+ />
+ </Link>
+ </Header>
+ <hr />
+
+ <Body onClick={(e: any) => e.stopPropagation()}>{children}</Body>
+ </div>
+ </FullSize>
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
new file mode 100644
index 000000000..6f71b9d2e
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.stories.tsx
@@ -0,0 +1,116 @@
+/*
+ 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 { WalletContractData } from "@gnu-taler/taler-wallet-core";
+import { createExample } from "../test-utils.js";
+import {
+ ErrorView,
+ HiddenView,
+ LoadingView,
+ ShowView,
+} from "./ShowFullContractTermPopup.js";
+
+export default {
+ title: "component/ShowFullContractTermPopup",
+};
+
+const cd: WalletContractData = {
+ amount: {
+ currency: "ARS",
+ fraction: 0,
+ value: 2,
+ },
+ contractTermsHash:
+ "92X0KSJPZ8XS2XECCGFWTCGW8XMFCXTT2S6WHZDP6H9Y3TSKMTHY94WXEWDERTNN5XWCYGW4VN5CF2D4846HXTW7P06J4CZMHCWKC9G",
+ fulfillmentUrl: "",
+ merchantBaseUrl: "https://merchant-backend.taler.ar/",
+ merchantPub: "JZYHJ13M91GMSQMT75J8Q6ZN0QP8XF8CRHR7K5MMWYE8JQB6AAPG",
+ merchantSig:
+ "0YA1WETV15R6K8QKS79QA3QMT16010F42Q49VSKYQ71HVQKAG0A4ZJCA4YTKHE9EA5SP156TJSKZEJJJ87305N6PS80PC48RNKYZE08",
+ orderId: "2022.220-0281XKKB8W7YE",
+ summary: "w",
+ maxWireFee: {
+ currency: "ARS",
+ fraction: 0,
+ value: 1,
+ },
+ payDeadline: {
+ t_s: 1660002673,
+ },
+ refundDeadline: {
+ t_s: 1660002673,
+ },
+ wireFeeAmortization: 1,
+ allowedAuditors: [
+ {
+ auditorBaseUrl: "https://auditor.taler.ar/",
+ auditorPub: "0000000000000000000000000000000000000000000000000000",
+ },
+ ],
+ allowedExchanges: [
+ {
+ exchangeBaseUrl: "https://exchange.taler.ar/",
+ exchangePub: "1C2EYE90PYDNVRTQ25A3PA0KW5W4WPAJNNQHVHV49PT6W5CERFV0",
+ },
+ ],
+ timestamp: {
+ t_s: 1659972710,
+ },
+ wireMethod: "x-taler-bank",
+ wireInfoHash:
+ "QDT28374ZHYJ59WQFZ3TW1D5WKJVDYHQT86VHED3TNMB15ANJSKXDYPPNX01348KDYCX6T4WXA5A8FJJ8YWNEB1JW726C1JPKHM89DR",
+ maxDepositFee: {
+ currency: "ARS",
+ fraction: 0,
+ value: 1,
+ },
+ merchant: {
+ name: "Default",
+ address: {
+ country: "ar",
+ },
+ jurisdiction: {
+ country: "ar",
+ },
+ },
+ products: [],
+ autoRefund: undefined,
+ summaryI18n: undefined,
+ deliveryDate: undefined,
+ deliveryLocation: undefined,
+};
+
+export const ShowingSimpleOrder = createExample(ShowView, {
+ contractTerms: cd,
+});
+export const Error = createExample(ErrorView, {
+ proposalId: "asd",
+ error: {
+ hasError: true,
+ message: "message",
+ operational: false,
+ // details: {
+ // code: 123,
+ // },
+ },
+});
+export const Loading = createExample(LoadingView, {});
+export const Hidden = createExample(HiddenView, {});
diff --git a/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
new file mode 100644
index 000000000..b7d8376bd
--- /dev/null
+++ b/packages/taler-wallet-webextension/src/components/ShowFullContractTermPopup.tsx
@@ -0,0 +1,385 @@
+/*
+ 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 { AbsoluteTime, Duration, Location } from "@gnu-taler/taler-util";
+import { WalletContractData } from "@gnu-taler/taler-wallet-core";
+import { styled } from "@linaria/react";
+import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { Loading } from "../components/Loading.js";
+import { LoadingError } from "../components/LoadingError.js";
+import { Modal } from "../components/Modal.js";
+import { Time } from "../components/Time.js";
+import { useTranslationContext } from "../context/translation.js";
+import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js";
+import { ButtonHandler } from "../mui/handlers.js";
+import { compose, StateViewMap } from "../utils/index.js";
+import * as wxApi from "../wxApi.js";
+import { Amount } from "./Amount.js";
+import { Link, LinkPrimary } from "./styled/index.js";
+
+const ContractTermsTable = styled.table`
+ width: 100%;
+ border-spacing: 0px;
+ & > tr > td {
+ padding: 5px;
+ }
+ & > tr > td:nth-child(2n) {
+ text-align: right;
+ }
+ & > tr:nth-child(2n) {
+ background: #ebebeb;
+ }
+`;
+
+function locationAsText(l: Location | undefined): VNode {
+ if (!l) return <span />;
+ const lines = [
+ ...(l.address_lines || []).map((e) => [e]),
+ [l.town_location, l.town, l.street],
+ [l.building_name, l.building_number],
+ [l.country, l.country_subdivision],
+ [l.district, l.post_code],
+ ];
+ //remove all missing value
+ //then remove all empty lines
+ const curated = lines
+ .map((l) => l.filter((v) => !!v))
+ .filter((l) => l.length > 0);
+ return (
+ <span>
+ {curated.map((c, i) => (
+ <div key={i}>{c.join(",")}</div>
+ ))}
+ </span>
+ );
+}
+
+type State = States.Loading | States.Error | States.Hidden | States.Show;
+
+namespace States {
+ export interface Loading {
+ status: "loading";
+ hideHandler: ButtonHandler;
+ }
+ export interface Error {
+ status: "error";
+ proposalId: string;
+ error: HookError;
+ hideHandler: ButtonHandler;
+ }
+ export interface Hidden {
+ status: "hidden";
+ showHandler: ButtonHandler;
+ }
+ export interface Show {
+ status: "show";
+ hideHandler: ButtonHandler;
+ contractTerms: WalletContractData;
+ }
+}
+
+interface Props {
+ proposalId: string;
+}
+
+function useComponentState({ proposalId }: Props, api: typeof wxApi): State {
+ const [show, setShow] = useState(false);
+ const hook = useAsyncAsHook(async () => {
+ if (!show) return undefined;
+ return await api.getContractTermsDetails(proposalId);
+ }, [show]);
+
+ const hideHandler = {
+ onClick: async () => setShow(false),
+ };
+ const showHandler = {
+ onClick: async () => setShow(true),
+ };
+ if (!show) {
+ return {
+ status: "hidden",
+ showHandler,
+ };
+ }
+ if (!hook) return { status: "loading", hideHandler };
+ if (hook.hasError)
+ return { status: "error", proposalId, error: hook, hideHandler };
+ if (!hook.response) return { status: "loading", hideHandler };
+ return {
+ status: "show",
+ contractTerms: hook.response,
+ hideHandler,
+ };
+}
+
+const viewMapping: StateViewMap<State> = {
+ loading: LoadingView,
+ error: ErrorView,
+ show: ShowView,
+ hidden: HiddenView,
+};
+
+export const ShowFullContractTermPopup = compose(
+ "ShowFullContractTermPopup",
+ (p: Props) => useComponentState(p, wxApi),
+ viewMapping,
+);
+
+export function LoadingView({ hideHandler }: States.Loading): VNode {
+ return (
+ <Modal title="Full detail" onClose={hideHandler}>
+ <Loading />
+ </Modal>
+ );
+}
+
+export function ErrorView({
+ hideHandler,
+ error,
+ proposalId,
+}: States.Error): VNode {
+ const { i18n } = useTranslationContext();
+ return (
+ <Modal title="Full detail" onClose={hideHandler}>
+ <LoadingError
+ title={
+ <i18n.Translate>
+ Could not load purchase proposal details
+ </i18n.Translate>
+ }
+ error={error}
+ />
+ </Modal>
+ );
+}
+
+export function HiddenView({ showHandler }: States.Hidden): VNode {
+ return <Link onClick={showHandler?.onClick}>Show full details</Link>;
+}
+
+export function ShowView({ contractTerms, hideHandler }: States.Show): VNode {
+ const createdAt = AbsoluteTime.fromTimestamp(contractTerms.timestamp);
+
+ return (
+ <Modal title="Full detail" onClose={hideHandler}>
+ <div style={{ overflowY: "auto", height: "95%", padding: 5 }}>
+ <ContractTermsTable>
+ <tr>
+ <td>Order Id</td>
+ <td>{contractTerms.orderId}</td>
+ </tr>
+ <tr>
+ <td>Summary</td>
+ <td>{contractTerms.summary}</td>
+ </tr>
+ <tr>
+ <td>Amount</td>
+ <td>
+ <Amount value={contractTerms.amount} />
+ </td>
+ </tr>
+ <tr>
+ <td>Merchant name</td>
+ <td>{contractTerms.merchant.name}</td>
+ </tr>
+ <tr>
+ <td>Merchant jurisdiction</td>
+ <td>{locationAsText(contractTerms.merchant.jurisdiction)}</td>
+ </tr>
+ <tr>
+ <td>Merchant address</td>
+ <td>{locationAsText(contractTerms.merchant.address)}</td>
+ </tr>
+ <tr>
+ <td>Merchant logo</td>
+ <td>
+ <div>
+ <img
+ src={contractTerms.merchant.logo}
+ style={{ width: 64, height: 64, margin: 4 }}
+ />
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Merchant website</td>
+ <td>{contractTerms.merchant.website}</td>
+ </tr>
+ <tr>
+ <td>Merchant email</td>
+ <td>{contractTerms.merchant.email}</td>
+ </tr>
+ <tr>
+ <td>Merchant public key</td>
+ <td>
+ <span title={contractTerms.merchantPub}>
+ {contractTerms.merchantPub.substring(0, 6)}...
+ </span>
+ </td>
+ </tr>
+ <tr>
+ <td>Delivery date</td>
+ <td>
+ {contractTerms.deliveryDate && (
+ <Time
+ timestamp={AbsoluteTime.fromTimestamp(
+ contractTerms.deliveryDate,
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ )}
+ </td>
+ </tr>
+ <tr>
+ <td>Delivery location</td>
+ <td>{locationAsText(contractTerms.deliveryLocation)}</td>
+ </tr>
+ <tr>
+ <td>Products</td>
+ <td>
+ {!contractTerms.products || contractTerms.products.length === 0
+ ? "none"
+ : contractTerms.products
+ .map((p) => `${p.description} x ${p.quantity}`)
+ .join(", ")}
+ </td>
+ </tr>
+ <tr>
+ <td>Created at</td>
+ <td>
+ {contractTerms.timestamp && (
+ <Time
+ timestamp={AbsoluteTime.fromTimestamp(
+ contractTerms.timestamp,
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ )}
+ </td>
+ </tr>
+ <tr>
+ <td>Refund deadline</td>
+ <td>
+ {
+ <Time
+ timestamp={AbsoluteTime.fromTimestamp(
+ contractTerms.refundDeadline,
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ }
+ </td>
+ </tr>
+ <tr>
+ <td>Auto refund</td>
+ <td>
+ {
+ <Time
+ timestamp={AbsoluteTime.addDuration(
+ createdAt,
+ !contractTerms.autoRefund
+ ? Duration.getZero()
+ : Duration.fromTalerProtocolDuration(
+ contractTerms.autoRefund,
+ ),
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ }
+ </td>
+ </tr>
+ <tr>
+ <td>Pay deadline</td>
+ <td>
+ {
+ <Time
+ timestamp={AbsoluteTime.fromTimestamp(
+ contractTerms.payDeadline,
+ )}
+ format="dd MMMM yyyy, HH:mm"
+ />
+ }
+ </td>
+ </tr>
+ <tr>
+ <td>Fulfillment URL</td>
+ <td>{contractTerms.fulfillmentUrl}</td>
+ </tr>
+ <tr>
+ <td>Fulfillment message</td>
+ <td>{contractTerms.fulfillmentMessage}</td>
+ </tr>
+ {/* <tr>
+ <td>Public reorder URL</td>
+ <td>{contractTerms.public_reorder_url}</td>
+ </tr> */}
+ <tr>
+ <td>Max deposit fee</td>
+ <td>
+ <Amount value={contractTerms.maxDepositFee} />
+ </td>
+ </tr>
+ <tr>
+ <td>Max fee</td>
+ <td>
+ <Amount value={contractTerms.maxWireFee} />
+ </td>
+ </tr>
+ <tr>
+ <td>Minimum age</td>
+ <td>{contractTerms.minimumAge}</td>
+ </tr>
+ {/* <tr>
+ <td>Extra</td>
+ <td>
+ <pre>{contractTerms.}</pre>
+ </td>
+ </tr> */}
+ <tr>
+ <td>Wire fee amortization</td>
+ <td>{contractTerms.wireFeeAmortization}</td>
+ </tr>
+ <tr>
+ <td>Auditors</td>
+ <td>
+ {(contractTerms.allowedAuditors || []).map((e) => (
+ <Fragment key={e.auditorPub}>
+ <a href={e.auditorBaseUrl} title={e.auditorPub}>
+ {e.auditorPub.substring(0, 6)}...
+ </a>
+ &nbsp;
+ </Fragment>
+ ))}
+ </td>
+ </tr>
+ <tr>
+ <td>Exchanges</td>
+ <td>
+ {(contractTerms.allowedExchanges || []).map((e) => (
+ <Fragment key={e.exchangePub}>
+ <a href={e.exchangeBaseUrl} title={e.exchangePub}>
+ {e.exchangePub.substring(0, 6)}...
+ </a>
+ &nbsp;
+ </Fragment>
+ ))}
+ </td>
+ </tr>
+ </ContractTermsTable>
+ </div>
+ </Modal>
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/index.stories.tsx b/packages/taler-wallet-webextension/src/components/index.stories.tsx
index 053b27f79..901347e4f 100644
--- a/packages/taler-wallet-webextension/src/components/index.stories.tsx
+++ b/packages/taler-wallet-webextension/src/components/index.stories.tsx
@@ -19,8 +19,9 @@
* @author Sebastian Javier Marchano (sebasjm)
*/
- import * as a1 from "./Banner.stories.js";
+import * as a1 from "./Banner.stories.js";
import * as a2 from "./PendingTransactions.stories.js";
import * as a3 from "./Amount.stories.js";
+import * as a4 from "./ShowFullContractTermPopup.stories.js";
-export default [a1, a2, a3];
+export default [a1, a2, a3, a4];
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 928562fb6..ff4a5b4d5 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -40,8 +40,18 @@ export const WalletAction = styled.div`
& h1:first-child {
margin-top: 0;
}
+ & > * {
+ width: 600px;
+ }
section {
margin-bottom: 2em;
+ table td {
+ padding: 5px 5px;
+ }
+ table tr {
+ border-bottom: 1px solid black;
+ border-top: 1px solid black;
+ }
button {
margin-right: 8px;
margin-left: 8px;