/* 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 */ import { AbsoluteTime, Duration, Location, TransactionIdStr, WalletContractData, } from "@gnu-taler/taler-util"; import { WalletApiOperation } 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 { Modal } from "../components/Modal.js"; import { Time } from "../components/Time.js"; import { alertFromError, useAlertContext } from "../context/alert.js"; import { useBackendContext } from "../context/backend.js"; import { useTranslationContext } from "@gnu-taler/web-util/browser"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { ButtonHandler } from "../mui/handlers.js"; import { compose, StateViewMap } from "../utils/index.js"; import { Amount } from "./Amount.js"; import { ErrorAlertView } from "./CurrentAlerts.js"; import { Link } 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; overflow-wrap: anywhere; } & > tr:nth-child(2n) { background: #ebebeb; } `; function locationAsText(l: Location | undefined): VNode { if (!l) return ; 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 ( {curated.map((c, i) => (
{c.join(",")}
))}
); } type State = States.Loading | States.Error | States.Hidden | States.Show; export namespace States { export interface Loading { status: "loading"; hideHandler: ButtonHandler; } export interface Error { status: "error"; transactionId: string; error: HookError; hideHandler: ButtonHandler; } export interface Hidden { status: "hidden"; showHandler: ButtonHandler; } export interface Show { status: "show"; hideHandler: ButtonHandler; contractTerms: WalletContractData; } } interface Props { transactionId: TransactionIdStr; } function useComponentState({ transactionId }: Props): State { const api = useBackendContext(); const [show, setShow] = useState(false); const { pushAlertOnError } = useAlertContext(); const hook = useAsyncAsHook(async () => { if (!show) return undefined; return await api.wallet.call(WalletApiOperation.GetContractTermsDetails, { transactionId, }); }, [show]); const hideHandler = { onClick: pushAlertOnError(async () => setShow(false)), }; const showHandler = { onClick: pushAlertOnError(async () => setShow(true)), }; if (!show) { return { status: "hidden", showHandler, }; } if (!hook) return { status: "loading", hideHandler }; if (hook.hasError) return { status: "error", transactionId, error: hook, hideHandler }; if (!hook.response) return { status: "loading", hideHandler }; return { status: "show", contractTerms: hook.response, hideHandler, }; } const viewMapping: StateViewMap = { loading: LoadingView, error: ErrorView, show: ShowView, hidden: HiddenView, }; export const ShowFullContractTermPopup = compose( "ShowFullContractTermPopup", (p: Props) => useComponentState(p), viewMapping, ); export function LoadingView({ hideHandler }: States.Loading): VNode { return ( ); } export function ErrorView({ hideHandler, error, transactionId, }: States.Error): VNode { const { i18n } = useTranslationContext(); return ( ); } export function HiddenView({ showHandler }: States.Hidden): VNode { return Show full details; } export function ShowView({ contractTerms, hideHandler }: States.Show): VNode { const createdAt = AbsoluteTime.fromProtocolTimestamp(contractTerms.timestamp); const { i18n } = useTranslationContext(); return (
Order Id {contractTerms.orderId} Summary {contractTerms.summary} Amount Merchant name {contractTerms.merchant.name} Merchant jurisdiction {locationAsText(contractTerms.merchant.jurisdiction)} Merchant address {locationAsText(contractTerms.merchant.address)} Merchant logo
Merchant website {contractTerms.merchant.website} Merchant email {contractTerms.merchant.email} Merchant public key {contractTerms.merchantPub.substring(0, 6)}... {/* Delivery date {contractTerms.deliveryDate && (
); }