/* This file is part of TALER (C) 2015-2016 GNUnet e.V. TALER is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. TALER is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with TALER; see the file COPYING. If not, see */ /** * Page that shows refund status for purchases. * * @author sebasjm */ import { AmountJson, Amounts, NotificationType, Product, } from "@gnu-taler/taler-util"; import { h, VNode } from "preact"; import { useEffect, useState } from "preact/hooks"; import { Amount } from "../components/Amount.js"; import { Loading } from "../components/Loading.js"; import { LoadingError } from "../components/LoadingError.js"; import { LogoHeader } from "../components/LogoHeader.js"; import { Part } from "../components/Part.js"; import { ButtonSuccess, SubTitle, WalletAction, } from "../components/styled/index.js"; import { useTranslationContext } from "../context/translation.js"; import { HookError, useAsyncAsHook } from "../hooks/useAsyncAsHook.js"; import { Button } from "../mui/Button.js"; import { ButtonHandler } from "../mui/handlers.js"; import * as wxApi from "../wxApi.js"; import { ProductList } from "./Pay.js"; interface Props { talerRefundUri?: string; } export interface ViewProps { state: State; } export function View({ state }: ViewProps): VNode { const { i18n } = useTranslationContext(); if (state.status === "loading") { if (!state.hook) { return ; } return ( Could not load refund status} error={state.hook} /> ); } if (state.status === "ignored") { return ( Digital cash refund

You've ignored the tip.

); } if (state.status === "in-progress") { return ( Digital cash refund

The refund is in progress.

Total to refund} text={} kind="negative" /> Refunded} text={} kind="negative" />
{state.products && state.products.length ? (
) : undefined} {/*
*/}
); } if (state.status === "completed") { return ( Digital cash refund

this refund is already accepted.

Total to refunded} text={} kind="negative" />
); } return ( Digital cash refund

The merchant "{state.merchantName}" is offering you a refund.

Order amount} text={} kind="neutral" /> {Amounts.isNonZero(state.granted) && ( Already refunded} text={} kind="neutral" /> )} Refund offered} text={} kind="positive" />
{state.products && state.products.length ? (
) : undefined}
); } type State = Loading | Ready | Ignored | InProgress | Completed; interface Loading { status: "loading"; hook: HookError | undefined; } interface Ready { status: "ready"; hook: undefined; merchantName: string; products: Product[] | undefined; amount: AmountJson; awaitingAmount: AmountJson; granted: AmountJson; accept: ButtonHandler; ignore: ButtonHandler; orderId: string; } interface Ignored { status: "ignored"; hook: undefined; merchantName: string; } interface InProgress { status: "in-progress"; hook: undefined; merchantName: string; products: Product[] | undefined; amount: AmountJson; awaitingAmount: AmountJson; granted: AmountJson; } interface Completed { status: "completed"; hook: undefined; merchantName: string; products: Product[] | undefined; amount: AmountJson; granted: AmountJson; } export function useComponentState( talerRefundUri: string | undefined, api: typeof wxApi, ): State { const [ignored, setIgnored] = useState(false); const info = useAsyncAsHook(async () => { if (!talerRefundUri) throw Error("ERROR_NO-URI-FOR-REFUND"); const refund = await api.prepareRefund({ talerRefundUri }); return { refund, uri: talerRefundUri }; }); useEffect(() => { api.onUpdateNotification([NotificationType.RefreshMelted], () => { info?.retry(); }); }); if (!info || info.hasError) { return { status: "loading", hook: info, }; } const { refund, uri } = info.response; const doAccept = async (): Promise => { await api.applyRefund(uri); info.retry(); }; const doIgnore = async (): Promise => { setIgnored(true); }; if (ignored) { return { status: "ignored", hook: undefined, merchantName: info.response.refund.info.merchant.name, }; } const awaitingAmount = Amounts.parseOrThrow(refund.awaiting); if (Amounts.isZero(awaitingAmount)) { return { status: "completed", hook: undefined, amount: Amounts.parseOrThrow(info.response.refund.effectivePaid), granted: Amounts.parseOrThrow(info.response.refund.granted), merchantName: info.response.refund.info.merchant.name, products: info.response.refund.info.products, }; } if (refund.pending) { return { status: "in-progress", hook: undefined, awaitingAmount, amount: Amounts.parseOrThrow(info.response.refund.effectivePaid), granted: Amounts.parseOrThrow(info.response.refund.granted), merchantName: info.response.refund.info.merchant.name, products: info.response.refund.info.products, }; } return { status: "ready", hook: undefined, amount: Amounts.parseOrThrow(info.response.refund.effectivePaid), granted: Amounts.parseOrThrow(info.response.refund.granted), awaitingAmount, merchantName: info.response.refund.info.merchant.name, products: info.response.refund.info.products, orderId: info.response.refund.info.orderId, accept: { onClick: doAccept, }, ignore: { onClick: doIgnore, }, }; } export function RefundPage({ talerRefundUri }: Props): VNode { const { i18n } = useTranslationContext(); const state = useComponentState(talerRefundUri, wxApi); if (!talerRefundUri) { return ( missing taler refund uri ); } return ; } function ProgressBar({ value }: { value: number }): VNode { return (
); }