From b6e774585d32017e5f1ceeeb2b2e2a5e350354d3 Mon Sep 17 00:00:00 2001 From: Florian Dold Date: Sun, 28 May 2017 23:15:41 +0200 Subject: move webex specific things in their own directory --- src/webex/pages/confirm-contract.tsx | 242 +++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) create mode 100644 src/webex/pages/confirm-contract.tsx (limited to 'src/webex/pages/confirm-contract.tsx') diff --git a/src/webex/pages/confirm-contract.tsx b/src/webex/pages/confirm-contract.tsx new file mode 100644 index 000000000..011df27a1 --- /dev/null +++ b/src/webex/pages/confirm-contract.tsx @@ -0,0 +1,242 @@ +/* + This file is part of TALER + (C) 2015 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 shown to the user to confirm entering + * a contract. + */ + + +/** + * Imports. + */ +import * as i18n from "../../i18n"; +import { Contract, AmountJson, ExchangeRecord } from "../../types"; +import { OfferRecord } from "../../wallet"; + +import { renderContract } from "../renderHtml"; +import { getExchanges } from "../wxApi"; + +import * as React from "react"; +import * as ReactDOM from "react-dom"; +import URI = require("urijs"); + + +interface DetailState { + collapsed: boolean; +} + +interface DetailProps { + contract: Contract + collapsed: boolean + exchanges: null|ExchangeRecord[]; +} + + +class Details extends React.Component { + constructor(props: DetailProps) { + super(props); + console.log("new Details component created"); + this.state = { + collapsed: props.collapsed, + }; + + console.log("initial state:", this.state); + } + + render() { + if (this.state.collapsed) { + return ( +
+ +
+ ); + } else { + return ( +
+ +
+ {i18n.str`Accepted exchanges:`} +
    + {this.props.contract.exchanges.map( + e =>
  • {`${e.url}: ${e.master_pub}`}
  • )} +
+ {i18n.str`Exchanges in the wallet:`} +
    + {(this.props.exchanges || []).map( + (e: ExchangeRecord) => +
  • {`${e.baseUrl}: ${e.masterPublicKey}`}
  • )} +
+
+
); + } + } +} + +interface ContractPromptProps { + offerId: number; +} + +interface ContractPromptState { + offer: OfferRecord|null; + error: string|null; + payDisabled: boolean; + exchanges: null|ExchangeRecord[]; +} + +class ContractPrompt extends React.Component { + constructor() { + super(); + this.state = { + offer: null, + error: null, + payDisabled: true, + exchanges: null + } + } + + componentWillMount() { + this.update(); + } + + componentWillUnmount() { + // FIXME: abort running ops + } + + async update() { + let offer = await this.getOffer(); + this.setState({offer} as any); + this.checkPayment(); + let exchanges = await getExchanges(); + this.setState({exchanges} as any); + } + + getOffer(): Promise { + return new Promise((resolve, reject) => { + let msg = { + type: 'get-offer', + detail: { + offerId: this.props.offerId + } + }; + chrome.runtime.sendMessage(msg, (resp) => { + resolve(resp); + }); + }) + } + + checkPayment() { + let msg = { + type: 'check-pay', + detail: { + offer: this.state.offer + } + }; + chrome.runtime.sendMessage(msg, (resp) => { + if (resp.error) { + console.log("check-pay error", JSON.stringify(resp)); + switch (resp.error) { + case "coins-insufficient": + let msgInsufficient = i18n.str`You have insufficient funds of the requested currency in your wallet.`; + let msgNoMatch = i18n.str`You do not have any funds from an exchange that is accepted by this merchant. None of the exchanges accepted by the merchant is known to your wallet.`; + if (this.state.exchanges && this.state.offer) { + let acceptedExchangePubs = this.state.offer.contract.exchanges.map((e) => e.master_pub); + let ex = this.state.exchanges.find((e) => acceptedExchangePubs.indexOf(e.masterPublicKey) >= 0); + if (ex) { + this.setState({error: msgInsufficient}); + } else { + this.setState({error: msgNoMatch}); + } + } else { + this.setState({error: msgInsufficient}); + } + break; + default: + this.setState({error: `Error: ${resp.error}`}); + break; + } + this.setState({payDisabled: true}); + } else { + this.setState({payDisabled: false, error: null}); + } + this.setState({} as any); + window.setTimeout(() => this.checkPayment(), 500); + }); + } + + doPayment() { + let d = {offer: this.state.offer}; + chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => { + if (resp.error) { + console.log("confirm-pay error", JSON.stringify(resp)); + switch (resp.error) { + case "coins-insufficient": + this.setState({error: "You do not have enough coins of the requested currency."}); + break; + default: + this.setState({error: `Error: ${resp.error}`}); + break; + } + return; + } + let c = d.offer!.contract; + console.log("contract", c); + document.location.href = c.fulfillment_url; + }); + } + + + render() { + if (!this.state.offer) { + return ...; + } + let c = this.state.offer.contract; + return ( +
+
+ {renderContract(c)} +
+ +
+ {(this.state.error ?

{this.state.error}

:

)} +

+
+
+ ); + } +} + + +document.addEventListener("DOMContentLoaded", () => { + let url = new URI(document.location.href); + let query: any = URI.parseQuery(url.query()); + let offerId = JSON.parse(query.offerId); + + ReactDOM.render(, document.getElementById( + "contract")!); +}); -- cgit v1.2.3