From c35b3be7957a90bd1e861c0502736aa1eb7acfbf Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sat, 31 Aug 2019 13:27:12 +0200 Subject: refund view --- src/webex/messages.ts | 4 +- src/webex/pages/refund.html | 5 +- src/webex/pages/refund.tsx | 190 +++++++++++--------------------------------- src/webex/renderHtml.tsx | 2 +- src/webex/wxApi.ts | 9 ++- src/webex/wxBackend.ts | 18 +++-- 6 files changed, 69 insertions(+), 159 deletions(-) (limited to 'src/webex') diff --git a/src/webex/messages.ts b/src/webex/messages.ts index 7b3041ac2..7e99cfc77 100644 --- a/src/webex/messages.ts +++ b/src/webex/messages.ts @@ -157,9 +157,9 @@ export interface MessageMap { request: { reportUid: string }; response: void; }; - "get-purchase": { + "get-purchase-details": { request: { contractTermsHash: string }; - response: dbTypes.PurchaseRecord; + response: walletTypes.PurchaseDetails; }; "accept-tip": { request: { talerTipUri: string }; diff --git a/src/webex/pages/refund.html b/src/webex/pages/refund.html index f97dc9d6c..203fda21b 100644 --- a/src/webex/pages/refund.html +++ b/src/webex/pages/refund.html @@ -13,6 +13,9 @@ -
+
+

GNU Taler Wallet

+
+
diff --git a/src/webex/pages/refund.tsx b/src/webex/pages/refund.tsx index 57d740486..9a7828edb 100644 --- a/src/webex/pages/refund.tsx +++ b/src/webex/pages/refund.tsx @@ -14,177 +14,74 @@ TALER; see the file COPYING. If not, see */ - /** * Page that shows refund status for purchases. * * @author Florian Dold */ - -import * as React from "react"; -import * as ReactDOM from "react-dom"; +import React, { useEffect, useState } from "react"; +import ReactDOM from "react-dom"; import URI = require("urijs"); -import * as dbTypes from "../../dbTypes"; - -import { AmountJson } from "../../amounts"; -import * as Amounts from "../../amounts"; - -import * as timer from "../../timer"; - -import { AmountDisplay } from "../renderHtml"; import * as wxApi from "../wxApi"; +import { PurchaseDetails } from "../../walletTypes"; +import { AmountView } from "../renderHtml"; + +function RefundStatusView(props: { talerRefundUri: string }) { + const [applied, setApplied] = useState(false); + const [purchaseDetails, setPurchaseDetails] = useState< + PurchaseDetails | undefined + >(undefined); + const [errMsg, setErrMsg] = useState(undefined); + + useEffect(() => { + const doFetch = async () => { + try { + const hc = await wxApi.applyRefund(props.talerRefundUri); + setApplied(true); + const r = await wxApi.getPurchaseDetails(hc); + setPurchaseDetails(r); + } catch (e) { + console.error(e); + setErrMsg(e.message); + console.log("err message", e.message); + } + }; + doFetch(); + }); -interface RefundStatusViewProps { - contractTermsHash?: string; - refundUrl?: string; -} - -interface RefundStatusViewState { - contractTermsHash?: string; - purchase?: dbTypes.PurchaseRecord; - refundFees?: AmountJson; - gotResult: boolean; -} - -interface RefundDetailProps { - purchase: dbTypes.PurchaseRecord; - /** - * Full refund fees (including refreshing) so far, or undefined if no refund - * permission was processed yet - */ - fullRefundFees?: AmountJson; -} - -const RefundDetail = ({purchase, fullRefundFees}: RefundDetailProps) => { - const pendingKeys = Object.keys(purchase.refundsPending); - const doneKeys = Object.keys(purchase.refundsDone); - if (pendingKeys.length === 0 && doneKeys.length === 0) { - return

No refunds

; - } + console.log("rendering"); - const firstRefundKey = [...pendingKeys, ...doneKeys][0]; - if (!firstRefundKey) { - return

Waiting for refunds ...

; - } - const allRefunds = { ...purchase.refundsDone, ...purchase.refundsPending }; - const currency = Amounts.parseOrThrow(allRefunds[firstRefundKey].refund_amount).currency; - if (!currency) { - throw Error("invariant"); + if (errMsg) { + return Error: {errMsg}; } - let amountPending = Amounts.getZero(currency); - for (const k of pendingKeys) { - const refundAmount = Amounts.parseOrThrow(purchase.refundsPending[k].refund_amount); - amountPending = Amounts.add(amountPending, refundAmount).amount; + if (!applied || !purchaseDetails) { + return Updating refund status; } - let amountDone = Amounts.getZero(currency); - for (const k of doneKeys) { - const refundAmount = Amounts.parseOrThrow(purchase.refundsDone[k].refund_amount); - amountDone = Amounts.add(amountDone, refundAmount).amount; - } - - const hasPending = amountPending.fraction !== 0 || amountPending.value !== 0; return ( -
- {hasPending ?

Refund pending:

: null} + <> +

Refund Status

- Refund received: {" "} - (refund fees: {fullRefundFees ? : "??" }) + The product {purchaseDetails.contractTerms.summary!} has + received a total refund of .

-
+

+ Note that additional fees from the exchange may apply. +

+ ); -}; - -class RefundStatusView extends React.Component { - - constructor(props: RefundStatusViewProps) { - super(props); - this.state = { gotResult: false }; - } - - componentDidMount() { - this.update(); - const port = chrome.runtime.connect(); - port.onMessage.addListener((msg: any) => { - if (msg.notify) { - console.log("got notified"); - this.update(); - } - }); - // Just to be safe: update every second, in case we miss a notification - // from the background page. - timer.after(1000, () => this.update()); - } - - render(): JSX.Element { - if (!this.props.contractTermsHash && !this.props.refundUrl) { - return ( -
- Error: Neither contract terms hash nor refund url given. -
- ); - } - const purchase = this.state.purchase; - if (!purchase) { - let message; - if (this.state.gotResult) { - message = No purchase with contract terms hash {this.props.contractTermsHash} found; - } else { - message = ...; - } - return
{message}
; - } - const merchantName = purchase.contractTerms.merchant.name || "(unknown)"; - const summary = purchase.contractTerms.summary || purchase.contractTerms.order_id; - return ( -
-

Refund Status

-

- Status of purchase {summary} from merchant {merchantName}{" "} - (order id {purchase.contractTerms.order_id}). -

-

Total amount:

- {purchase.finished - ? - :

Purchase not completed.

} -
- ); - } - - async update() { - let contractTermsHash = this.state.contractTermsHash; - if (!contractTermsHash) { - const refundUrl = this.props.refundUrl; - if (!refundUrl) { - console.error("neither contractTermsHash nor refundUrl is given"); - return; - } - contractTermsHash = await wxApi.acceptRefund(refundUrl); - this.setState({ contractTermsHash }); - } - const purchase = await wxApi.getPurchase(contractTermsHash); - console.log("got purchase", purchase); - // We got a result, but it might be undefined if not found in DB. - this.setState({ purchase, gotResult: true }); - const refundsDone = Object.keys(purchase.refundsDone).map((x) => purchase.refundsDone[x]); - if (refundsDone.length) { - const refundFees = await wxApi.getFullRefundFees({ refundPermissions: refundsDone }); - this.setState({ purchase, gotResult: true, refundFees }); - } - } } - async function main() { const url = new URI(document.location.href); const query: any = URI.parseQuery(url.query()); const container = document.getElementById("container"); if (!container) { - console.error("fatal: can't mount component, countainer missing"); + console.error("fatal: can't mount component, container missing"); return; } @@ -194,7 +91,10 @@ async function main() { return; } - ReactDOM.render(, container); + ReactDOM.render( + , + container, + ); } document.addEventListener("DOMContentLoaded", () => main()); diff --git a/src/webex/renderHtml.tsx b/src/webex/renderHtml.tsx index 867fb440f..1c50aa1ad 100644 --- a/src/webex/renderHtml.tsx +++ b/src/webex/renderHtml.tsx @@ -62,7 +62,7 @@ export function renderAmount(amount: AmountJson | string) { return {x} {a.currency}; } -export const AmountDisplay = ({amount}: {amount: AmountJson | string}) => renderAmount(amount); +export const AmountView = ({amount}: {amount: AmountJson | string}) => renderAmount(amount); /** diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts index d2e8c94f1..7e4d17e37 100644 --- a/src/webex/wxApi.ts +++ b/src/webex/wxApi.ts @@ -41,6 +41,7 @@ import { SenderWireInfos, TipStatus, WalletBalance, + PurchaseDetails, } from "../walletTypes"; import { @@ -91,7 +92,7 @@ async function callBackend( return new Promise((resolve, reject) => { chrome.runtime.sendMessage({ type, detail }, (resp) => { if (typeof resp === "object" && resp && resp.error) { - const e = new WalletApiError(resp.message, resp); + const e = new WalletApiError(resp.error.message, resp.error); reject(e); } else { resolve(resp); @@ -318,8 +319,8 @@ export function getReport(reportUid: string): Promise { * Look up a purchase in the wallet database from * the contract terms hash. */ -export function getPurchase(contractTermsHash: string): Promise { - return callBackend("get-purchase", { contractTermsHash }); +export function getPurchaseDetails(contractTermsHash: string): Promise { + return callBackend("get-purchase-details", { contractTermsHash }); } @@ -356,7 +357,7 @@ export function downloadProposal(url: string): Promise { /** * Download a refund and accept it. */ -export function acceptRefund(refundUrl: string): Promise { +export function applyRefund(refundUrl: string): Promise { return callBackend("accept-refund", { refundUrl }); } diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts index 570a37586..ea43f65c2 100644 --- a/src/webex/wxBackend.ts +++ b/src/webex/wxBackend.ts @@ -62,7 +62,12 @@ function handleMessage( function assertNotFound(t: never): never { console.error(`Request type ${t as string} unknown`); console.error(`Request detail was ${detail}`); - return { error: "request unknown", requestType: type } as never; + return { + error: { + message: `request type ${t as string} unknown`, + requestType: type, + }, + } as never; } function needsWallet(): Wallet { if (!currentWallet) { @@ -264,12 +269,12 @@ function handleMessage( return; case "get-report": return logging.getReport(detail.reportUid); - case "get-purchase": { + case "get-purchase-details": { const contractTermsHash = detail.contractTermsHash; if (!contractTermsHash) { throw Error("contractTermsHash missing"); } - return needsWallet().getPurchase(contractTermsHash); + return needsWallet().getPurchaseDetails(contractTermsHash); } case "accept-refund": return needsWallet().applyRefund(detail.refundUrl); @@ -343,9 +348,10 @@ async function dispatch( } try { sendResponse({ - error: "exception", - message: e.message, - stack, + error: { + message: e.message, + stack, + } }); } catch (e) { console.log(e); -- cgit v1.2.3