gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[GNUnet-SVN] [taler-wallet-webex] 02/02: less ad-hoc messaging, fix some


From: gnunet
Subject: [GNUnet-SVN] [taler-wallet-webex] 02/02: less ad-hoc messaging, fix some lint warnings
Date: Mon, 29 May 2017 16:28:23 +0200

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-webex.

commit 1c3346cd534143f4dd56a625b963a1a3acfa83d1
Author: Florian Dold <address@hidden>
AuthorDate: Mon May 29 16:27:53 2017 +0200

    less ad-hoc messaging, fix some lint warnings
---
 src/crypto/cryptoApi.ts                    |   2 +-
 src/crypto/cryptoWorker.ts                 |   2 +-
 src/i18n.tsx                               |  46 ++++-----
 src/types.ts                               |  52 ++++++++++
 src/wallet.ts                              |  73 +++----------
 src/webex/pages/confirm-contract.tsx       | 117 +++++++++------------
 src/webex/pages/confirm-create-reserve.tsx | 160 ++++++++++++++---------------
 src/webex/pages/error.tsx                  |   4 +-
 src/webex/pages/logs.tsx                   |  13 ++-
 src/webex/pages/payback.tsx                |  33 +++---
 src/webex/wxApi.ts                         |  26 +++++
 src/webex/wxBackend.ts                     |   2 +-
 12 files changed, 266 insertions(+), 264 deletions(-)

diff --git a/src/crypto/cryptoApi.ts b/src/crypto/cryptoApi.ts
index 3c5eb84d..b5d7d4fb 100644
--- a/src/crypto/cryptoApi.ts
+++ b/src/crypto/cryptoApi.ts
@@ -27,6 +27,7 @@ import {
   AmountJson,
   CoinRecord,
   DenominationRecord,
+  OfferRecord,
   PayCoinInfo,
   PaybackRequest,
   PreCoinRecord,
@@ -37,7 +38,6 @@ import {
 
 import {
   CoinWithDenom,
-  OfferRecord,
 } from "../wallet";
 
 import * as timer from "../timer";
diff --git a/src/crypto/cryptoWorker.ts b/src/crypto/cryptoWorker.ts
index 1a337446..85a0425b 100644
--- a/src/crypto/cryptoWorker.ts
+++ b/src/crypto/cryptoWorker.ts
@@ -29,6 +29,7 @@ import {
   CoinRecord,
   CoinStatus,
   DenominationRecord,
+  OfferRecord,
   PayCoinInfo,
   PaybackRequest,
   PreCoinRecord,
@@ -39,7 +40,6 @@ import {
 } from "../types";
 import {
   CoinWithDenom,
-  OfferRecord,
 } from "../wallet";
 
 import {
diff --git a/src/i18n.tsx b/src/i18n.tsx
index e5b9c398..8c3d5419 100644
--- a/src/i18n.tsx
+++ b/src/i18n.tsx
@@ -40,7 +40,7 @@ if (!strings[lang]) {
   console.log(`language ${lang} not found, defaulting to english`);
 }
 
-let jed = new jedLib.Jed(strings[lang]);
+const jed = new jedLib.Jed(strings[lang]);
 
 
 /**
@@ -62,8 +62,8 @@ function toI18nString(strings: ReadonlyArray<string>) {
  * Internationalize a string template with arbitrary serialized values.
  */
 export function str(strings: TemplateStringsArray, ...values: any[]) {
-  let str = toI18nString(strings);
-  let tr = jed.translate(str).ifPlural(1, str).fetch(...values);
+  const str = toI18nString(strings);
+  const tr = jed.translate(str).ifPlural(1, str).fetch(...values);
   return tr;
 }
 
@@ -75,7 +75,7 @@ interface TranslateSwitchProps {
 
 function stringifyChildren(children: any): string {
   let n = 1;
-  let ss = React.Children.map(children, (c) => {
+  const ss = React.Children.map(children, (c) => {
     if (typeof c === "string") {
       return c;
     }
@@ -113,23 +113,23 @@ interface TranslateProps {
  */
 export class Translate extends React.Component<TranslateProps,void> {
   render(): JSX.Element {
-    let s = stringifyChildren(this.props.children);
-    let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
-    let childArray = React.Children.toArray(this.props.children!);
+    const s = stringifyChildren(this.props.children);
+    const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
+    const childArray = React.Children.toArray(this.props.children!);
     for (let i = 0; i < childArray.length - 1; ++i) {
       if ((typeof childArray[i]) == "string" && (typeof childArray[i+1]) == 
"string") {
         childArray[i+1] = (childArray[i] as string).concat(childArray[i+1] as 
string);
         childArray.splice(i,1);
       }
     }
-    let result = [];
+    const result = [];
     while (childArray.length > 0) {
-      let x = childArray.shift();
+      const x = childArray.shift();
       if (x === undefined) {
         continue;
       }
       if (typeof x === "string") {
-        let t = tr.shift();
+        const t = tr.shift();
         result.push(t);
       } else {
         result.push(x);
@@ -159,7 +159,7 @@ export class TranslateSwitch extends 
React.Component<TranslateSwitchProps,void>{
   render(): JSX.Element {
     let singular: React.ReactElement<TranslationPluralProps> | undefined;
     let plural: React.ReactElement<TranslationPluralProps> | undefined;
-    let children = this.props.children;
+    const children = this.props.children;
     if (children) {
       React.Children.forEach(children, (child: any) => {
         if (child.type == TranslatePlural) {
@@ -192,23 +192,23 @@ interface TranslationPluralProps {
  */
 export class TranslatePlural extends 
React.Component<TranslationPluralProps,void> {
   render(): JSX.Element {
-    let s = stringifyChildren(this.props.children);
-    let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
-    let childArray = React.Children.toArray(this.props.children!);
+    const s = stringifyChildren(this.props.children);
+    const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
+    const childArray = React.Children.toArray(this.props.children!);
     for (let i = 0; i < childArray.length - 1; ++i) {
       if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == 
"string") {
         childArray[i+i] = childArray[i] as string + childArray[i + 1] as 
string;
         childArray.splice(i,1);
       }
     }
-    let result = [];
+    const result = [];
     while (childArray.length > 0) {
-      let x = childArray.shift();
+      const x = childArray.shift();
       if (x === undefined) {
         continue;
       }
       if (typeof x === "string") {
-        let t = tr.shift();
+        const t = tr.shift();
         result.push(t);
       } else {
         result.push(x);
@@ -224,23 +224,23 @@ export class TranslatePlural extends 
React.Component<TranslationPluralProps,void
  */
 export class TranslateSingular extends 
React.Component<TranslationPluralProps,void> {
   render(): JSX.Element {
-    let s = stringifyChildren(this.props.children);
-    let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
-    let childArray = React.Children.toArray(this.props.children!);
+    const s = stringifyChildren(this.props.children);
+    const tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: 
number) => i % 2 == 0);
+    const childArray = React.Children.toArray(this.props.children!);
     for (let i = 0; i < childArray.length - 1; ++i) {
       if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == 
"string") {
         childArray[i+i] = childArray[i] as string + childArray[i + 1] as 
string;
         childArray.splice(i,1);
       }
     }
-    let result = [];
+    const result = [];
     while (childArray.length > 0) {
-      let x = childArray.shift();
+      const x = childArray.shift();
       if (x === undefined) {
         continue;
       }
       if (typeof x === "string") {
-        let t = tr.shift();
+        const t = tr.shift();
         result.push(t);
       } else {
         result.push(x);
diff --git a/src/types.ts b/src/types.ts
index 0371aab7..8b5f4063 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -1075,6 +1075,51 @@ export class Contract {
 
 
 /**
+ * Offer record, stored in the wallet's database.
+ */
address@hidden()
+export class OfferRecord {
+  /**
+   * The contract that was offered by the merchant.
+   */
+  @Checkable.Value(Contract)
+  contract: Contract;
+
+  /**
+   * Signature by the merchant over the contract details.
+   */
+  @Checkable.String
+  merchant_sig: string;
+
+  /**
+   * Hash of the contract terms.
+   */
+  @Checkable.String
+  H_contract: string;
+
+  /**
+   * Time when the offer was made.
+   */
+  @Checkable.Number
+  offer_time: number;
+
+  /**
+   * Serial ID when the offer is stored in the wallet DB.
+   */
+  @Checkable.Optional(Checkable.Number)
+  id?: number;
+
+  /**
+   * Verify that a value matches the schema of this class and convert it into a
+   * member.
+   */
+  static checked: (obj: any) => OfferRecord;
+}
+
+
+
+
+/**
  * Wire fee for one wire method as stored in the
  * wallet's database.
  */
@@ -1333,3 +1378,10 @@ export interface Notifier {
 export function mkAmount(value: number, fraction: number, currency: string): 
AmountJson {
   return {value, fraction, currency};
 }
+
+/**
+ * Possible responses for checkPay.
+ */
+export type CheckPayResult = "paid" | "payment-possible" | 
"insufficient-balance";
+
+export type ConfirmPayResult = "paid" | "insufficient-balance";
diff --git a/src/wallet.ts b/src/wallet.ts
index 743042b9..5564162b 100644
--- a/src/wallet.ts
+++ b/src/wallet.ts
@@ -50,9 +50,11 @@ import {
   Amounts,
   Auditor,
   AuditorRecord,
+  CheckPayResult,
   CoinPaySig,
   CoinRecord,
   CoinStatus,
+  ConfirmPayResult,
   Contract,
   CreateReserveResponse,
   CurrencyRecord,
@@ -63,6 +65,7 @@ import {
   ExchangeRecord,
   ExchangeWireFeesRecord,
   Notifier,
+  OfferRecord,
   PayCoinInfo,
   PaybackConfirmation,
   PreCoinRecord,
@@ -272,48 +275,6 @@ export class ConfirmReserveRequest {
 
 
 /**
- * Offer record, stored in the wallet's database.
- */
address@hidden()
-export class OfferRecord {
-  /**
-   * The contract that was offered by the merchant.
-   */
-  @Checkable.Value(Contract)
-  contract: Contract;
-
-  /**
-   * Signature by the merchant over the contract details.
-   */
-  @Checkable.String
-  merchant_sig: string;
-
-  /**
-   * Hash of the contract terms.
-   */
-  @Checkable.String
-  H_contract: string;
-
-  /**
-   * Time when the offer was made.
-   */
-  @Checkable.Number
-  offer_time: number;
-
-  /**
-   * Serial ID when the offer is stored in the wallet DB.
-   */
-  @Checkable.Optional(Checkable.Number)
-  id?: number;
-
-  /**
-   * Verify that a value matches the schema of this class and convert it into a
-   * member.
-   */
-  static checked: (obj: any) => OfferRecord;
-}
-
-/**
  * Activity history record.
  */
 export interface HistoryRecord {
@@ -981,14 +942,14 @@ export class Wallet {
    * Add a contract to the wallet and sign coins,
    * but do not send them yet.
    */
-  async confirmPay(offer: OfferRecord): Promise<any> {
+  async confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> {
     console.log("executing confirmPay");
 
     const transaction = await this.q().get(Stores.transactions, 
offer.H_contract);
 
     if (transaction) {
       // Already payed ...
-      return {};
+      return "paid";
     }
 
     const res = await this.getCoinsForPayment({
@@ -1007,29 +968,25 @@ export class Wallet {
 
     if (!res) {
       console.log("not confirming payment, insufficient coins");
-      return {
-        error: "coins-insufficient",
-      };
+      return "insufficient-balance";
     }
     const {exchangeUrl, cds} = res;
 
     const ds = await this.cryptoApi.signDeposit(offer, cds);
-    await this.recordConfirmPay(offer,
-                                ds,
-                                exchangeUrl);
-    return {};
+    await this.recordConfirmPay(offer, ds, exchangeUrl);
+    return "paid";
   }
 
 
   /**
-   * Add a contract to the wallet and sign coins,
-   * but do not send them yet.
+   * Check if payment for an offer is possible, or if the offer has already
+   * been payed for.
    */
-  async checkPay(offer: OfferRecord): Promise<any> {
+  async checkPay(offer: OfferRecord): Promise<CheckPayResult> {
     // First check if we already payed for it.
     const transaction = await this.q().get(Stores.transactions, 
offer.H_contract);
     if (transaction) {
-      return {isPayed: true};
+      return "insufficient-balance";
     }
 
     // If not already payed, check if we could pay for it.
@@ -1046,11 +1003,9 @@ export class Wallet {
 
     if (!res) {
       console.log("not confirming payment, insufficient coins");
-      return {
-        error: "coins-insufficient",
-      };
+      return "insufficient-balance";
     }
-    return {isPayed: false};
+    return "payment-possible";
   }
 
 
diff --git a/src/webex/pages/confirm-contract.tsx 
b/src/webex/pages/confirm-contract.tsx
index 011df27a..cc302584 100644
--- a/src/webex/pages/confirm-contract.tsx
+++ b/src/webex/pages/confirm-contract.tsx
@@ -24,11 +24,15 @@
  * Imports.
  */
 import * as i18n from "../../i18n";
-import { Contract, AmountJson, ExchangeRecord } from "../../types";
-import { OfferRecord } from "../../wallet";
+import {
+  AmountJson,
+  Contract,
+  ExchangeRecord,
+  OfferRecord,
+} from "../../types";
 
 import { renderContract } from "../renderHtml";
-import { getExchanges } from "../wxApi";
+import * as wxApi from "../wxApi";
 
 import * as React from "react";
 import * as ReactDOM from "react-dom";
@@ -125,85 +129,56 @@ class ContractPrompt extends 
React.Component<ContractPromptProps, ContractPrompt
   }
 
   async update() {
-    let offer = await this.getOffer();
+    let offer = await wxApi.getOffer(this.props.offerId);
     this.setState({offer} as any);
     this.checkPayment();
-    let exchanges = await getExchanges();
+    let exchanges = await wxApi.getExchanges();
     this.setState({exchanges} as any);
   }
 
-  getOffer(): Promise<OfferRecord> {
-    return new Promise<OfferRecord>((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;
+  async checkPayment() {
+    let offer = this.state.offer;
+    if (!offer) {
+      return;
+    }
+    const payStatus = await wxApi.checkPay(offer);
+
+    if (payStatus === "insufficient-balance") {
+      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});
         }
-        this.setState({payDisabled: true});
       } else {
-        this.setState({payDisabled: false, error: null});
+        this.setState({error: msgInsufficient});
       }
-      this.setState({} as any);
-      window.setTimeout(() => this.checkPayment(), 500);
-    });
+      this.setState({payDisabled: true});
+    } else {
+      this.setState({payDisabled: false, error: null});
+    }
+    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;
-        }
+  async doPayment() {
+    let offer = this.state.offer;
+    if (!offer) {
+      return;
+    }
+    const payStatus = await wxApi.confirmPay(offer);
+    switch (payStatus) {
+      case "insufficient-balance":
+        this.checkPayment();
         return;
-      }
-      let c = d.offer!.contract;
-      console.log("contract", c);
-      document.location.href = c.fulfillment_url;
-    });
+      case "paid":
+        console.log("contract", offer.contract);
+        document.location.href = offer.contract.fulfillment_url;
+        break;
+    }
   }
 
 
diff --git a/src/webex/pages/confirm-create-reserve.tsx 
b/src/webex/pages/confirm-create-reserve.tsx
index 6ece92e2..50a1045e 100644
--- a/src/webex/pages/confirm-create-reserve.tsx
+++ b/src/webex/pages/confirm-create-reserve.tsx
@@ -23,15 +23,23 @@
  */
 
 import {amountToPretty, canonicalizeBaseUrl} from "../../helpers";
+import * as i18n from "../../i18n";
 import {
-  AmountJson, CreateReserveResponse,
-  ReserveCreationInfo, Amounts,
-  Denomination, DenominationRecord, CurrencyRecord
+  AmountJson,
+  Amounts,
+  CreateReserveResponse,
+  CurrencyRecord,
+  Denomination,
+  DenominationRecord,
+  ReserveCreationInfo,
 } from "../../types";
-import * as i18n from "../../i18n";
 
-import {getReserveCreationInfo, getCurrency, getExchangeInfo} from "../wxApi";
 import {ImplicitStateComponent, StateHolder} from "../components";
+import {
+  getCurrency,
+  getExchangeInfo,
+  getReserveCreationInfo,
+} from "../wxApi";
 
 import * as React from "react";
 import * as ReactDOM from "react-dom";
@@ -46,8 +54,8 @@ function delay<T>(delayMs: number, value: T): Promise<T> {
 }
 
 class EventTrigger {
-  triggerResolve: any;
-  triggerPromise: Promise<boolean>;
+  private triggerResolve: any;
+  private triggerPromise: Promise<boolean>;
 
   constructor() {
     this.reset();
@@ -86,11 +94,11 @@ class Collapsible extends React.Component<CollapsibleProps, 
CollapsibleState> {
   }
   render() {
     const doOpen = (e: any) => {
-      this.setState({collapsed: false})
-      e.preventDefault()
+      this.setState({collapsed: false});
+      e.preventDefault();
     };
     const doClose = (e: any) => {
-      this.setState({collapsed: true})
+      this.setState({collapsed: true});
       e.preventDefault();
     };
     if (this.state.collapsed) {
@@ -113,7 +121,7 @@ function renderAuditorDetails(rci: 
ReserveCreationInfo|null) {
       </p>
     );
   }
-  if (rci.exchangeInfo.auditors.length == 0) {
+  if (rci.exchangeInfo.auditors.length === 0) {
     return (
       <p>
         The exchange is not audited by any auditors.
@@ -122,7 +130,7 @@ function renderAuditorDetails(rci: 
ReserveCreationInfo|null) {
   }
   return (
     <div>
-      {rci.exchangeInfo.auditors.map(a => (
+      {rci.exchangeInfo.auditors.map((a) => (
         <h3>Auditor {a.url}</h3>
       ))}
     </div>
@@ -138,14 +146,14 @@ function renderReserveCreationDetails(rci: 
ReserveCreationInfo|null) {
     );
   }
 
-  let denoms = rci.selectedDenoms;
+  const denoms = rci.selectedDenoms;
 
-  let countByPub: {[s: string]: number} = {};
-  let uniq: DenominationRecord[] = [];
+  const countByPub: {[s: string]: number} = {};
+  const uniq: DenominationRecord[] = [];
 
   denoms.forEach((x: DenominationRecord) => {
     let c = countByPub[x.denomPub] || 0;
-    if (c == 0) {
+    if (c === 0) {
       uniq.push(x);
     }
     c += 1;
@@ -177,19 +185,19 @@ function renderReserveCreationDetails(rci: 
ReserveCreationInfo|null) {
         </tr>
       </thead>,
       <tbody>
-      {rci!.wireFees.feesForType[s].map(f => (
+      {rci!.wireFees.feesForType[s].map((f) => (
         <tr>
           <td>{moment.unix(f.endStamp).format("llll")}</td>
           <td>{amountToPretty(f.wireFee)}</td>
           <td>{amountToPretty(f.closingFee)}</td>
         </tr>
       ))}
-      </tbody>
+      </tbody>,
     ];
   }
 
-  let withdrawFeeStr = amountToPretty(rci.withdrawFee);
-  let overheadStr = amountToPretty(rci.overhead);
+  const withdrawFeeStr = amountToPretty(rci.withdrawFee);
+  const overheadStr = amountToPretty(rci.overhead);
 
   return (
     <div>
@@ -221,28 +229,10 @@ function renderReserveCreationDetails(rci: 
ReserveCreationInfo|null) {
 }
 
 
-function getSuggestedExchange(currency: string): Promise<string> {
-  // TODO: make this request go to the wallet backend
-  // Right now, this is a stub.
-  const defaultExchange: {[s: string]: string} = {
-    "KUDOS": "https://exchange.demo.taler.net";,
-    "PUDOS": "https://exchange.test.taler.net";,
-  };
-
-  let exchange = defaultExchange[currency];
-
-  if (!exchange) {
-    exchange = ""
-  }
-
-  return Promise.resolve(exchange);
-}
-
-
 function WithdrawFee(props: {reserveCreationInfo: ReserveCreationInfo|null}): 
JSX.Element {
   if (props.reserveCreationInfo) {
-    let {overhead, withdrawFee} = props.reserveCreationInfo;
-    let totalCost = Amounts.add(overhead, withdrawFee).amount;
+    const {overhead, withdrawFee} = props.reserveCreationInfo;
+    const totalCost = Amounts.add(overhead, withdrawFee).amount;
     return <p>{i18n.str`Withdraw fees:`} {amountToPretty(totalCost)}</p>;
   }
   return <p />;
@@ -263,10 +253,10 @@ interface ManualSelectionProps {
 }
 
 class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
-  url: StateHolder<string> = this.makeState("");
-  errorMessage: StateHolder<string|null> = this.makeState(null);
-  isOkay: StateHolder<boolean> = this.makeState(false);
-  updateEvent = new EventTrigger();
+  private url: StateHolder<string> = this.makeState("");
+  private errorMessage: StateHolder<string|null> = this.makeState(null);
+  private isOkay: StateHolder<boolean> = this.makeState(false);
+  private updateEvent = new EventTrigger();
   constructor(p: ManualSelectionProps) {
     super(p);
     this.url(p.initialUrl);
@@ -300,23 +290,23 @@ class ManualSelection extends 
ImplicitStateComponent<ManualSelectionProps> {
     if (!this.url()) {
       return;
     }
-    let parsedUrl = new URI(this.url()!);
+    const parsedUrl = new URI(this.url()!);
     if (parsedUrl.is("relative")) {
       this.errorMessage(i18n.str`Error: URL may not be relative`);
       this.isOkay(false);
       return;
     }
     try {
-      let url = canonicalizeBaseUrl(this.url()!);
-      let r = await getExchangeInfo(url)
-      console.log("getExchangeInfo returned")
+      const url = canonicalizeBaseUrl(this.url()!);
+      const r = await getExchangeInfo(url);
+      console.log("getExchangeInfo returned");
       this.isOkay(true);
     } catch (e) {
       console.log("got error", e);
       if (e.hasOwnProperty("httpStatus")) {
         this.errorMessage(`Error: request failed with status ${e.httpStatus}`);
       } else if (e.hasOwnProperty("errorResponse")) {
-        let resp = e.errorResponse;
+        const resp = e.errorResponse;
         this.errorMessage(`Error: ${resp.error} (${resp.hint})`);
       } else {
         this.errorMessage("invalid exchange URL");
@@ -329,7 +319,7 @@ class ManualSelection extends 
ImplicitStateComponent<ManualSelectionProps> {
     this.errorMessage(null);
     this.isOkay(false);
     this.updateEvent.trigger();
-    let waited = await this.updateEvent.wait(200);
+    const waited = await this.updateEvent.wait(200);
     if (waited) {
       // Run the actual update if nobody else preempted us.
       this.update();
@@ -339,24 +329,24 @@ class ManualSelection extends 
ImplicitStateComponent<ManualSelectionProps> {
 
 
 class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> 
{
-  statusString: StateHolder<string|null> = this.makeState(null);
-  reserveCreationInfo: StateHolder<ReserveCreationInfo|null> = this.makeState(
+  private statusString: StateHolder<string|null> = this.makeState(null);
+  private reserveCreationInfo: StateHolder<ReserveCreationInfo|null> = 
this.makeState(
     null);
-  url: StateHolder<string|null> = this.makeState(null);
+  private url: StateHolder<string|null> = this.makeState(null);
 
-  selectingExchange: StateHolder<boolean> = this.makeState(false);
+  private selectingExchange: StateHolder<boolean> = this.makeState(false);
 
   constructor(props: ExchangeSelectionProps) {
     super(props);
-    let prefilledExchangesUrls = [];
+    const prefilledExchangesUrls = [];
     if (props.currencyRecord) {
-      let exchanges = props.currencyRecord.exchanges.map((x) => x.baseUrl);
+      const exchanges = props.currencyRecord.exchanges.map((x) => x.baseUrl);
       prefilledExchangesUrls.push(...exchanges);
     }
     if (props.suggestedExchangeUrl) {
       prefilledExchangesUrls.push(props.suggestedExchangeUrl);
     }
-    if (prefilledExchangesUrls.length != 0) {
+    if (prefilledExchangesUrls.length !== 0) {
       this.url(prefilledExchangesUrls[0]);
       this.forceReserveUpdate();
     } else {
@@ -365,9 +355,9 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
   }
 
   renderFeeStatus() {
-    let rci = this.reserveCreationInfo();
+    const rci = this.reserveCreationInfo();
     if (rci) {
-      let totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
+      const totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
       let trustMessage;
       if (rci.isTrusted) {
         trustMessage = (
@@ -404,7 +394,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
       );
     }
     if (this.url() && !this.statusString()) {
-      let shortName = new URI(this.url()!).host();
+      const shortName = new URI(this.url()!).host();
       return (
         <i18n.Translate wrap="p">
           Waiting for a response from
@@ -432,7 +422,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
       <div>
         {this.renderFeeStatus()}
         <button className="pure-button button-success"
-                disabled={this.reserveCreationInfo() == null}
+                disabled={this.reserveCreationInfo() === null}
                 onClick={() => this.confirmReserve()}>
           {i18n.str`Accept fees and withdraw`}
         </button>
@@ -460,7 +450,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
   }
 
   renderSelect() {
-    let exchanges = (this.props.currencyRecord && 
this.props.currencyRecord.exchanges) || [];
+    const exchanges = (this.props.currencyRecord && 
this.props.currencyRecord.exchanges) || [];
     console.log(exchanges);
     return (
       <div>
@@ -478,7 +468,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
         {exchanges.length > 0 && (
           <div>
             <h2>Known Exchanges</h2>
-            {exchanges.map(e => (
+            {exchanges.map((e) => (
               <button className="pure-button button-success" onClick={() => 
this.select(e.baseUrl)}>
               Select <strong>{e.baseUrl}</strong>
               </button>
@@ -519,8 +509,8 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
   async forceReserveUpdate() {
     this.reserveCreationInfo(null);
     try {
-      let url = canonicalizeBaseUrl(this.url()!);
-      let r = await getReserveCreationInfo(url,
+      const url = canonicalizeBaseUrl(this.url()!);
+      const r = await getReserveCreationInfo(url,
                                            this.props.amount);
       console.log("get exchange info resolved");
       this.reserveCreationInfo(r);
@@ -530,7 +520,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
       if (e.hasOwnProperty("httpStatus")) {
         this.statusString(`Error: request failed with status ${e.httpStatus}`);
       } else if (e.hasOwnProperty("errorResponse")) {
-        let resp = e.errorResponse;
+        const resp = e.errorResponse;
         this.statusString(`Error: ${resp.error} (${resp.hint})`);
       }
     }
@@ -546,13 +536,13 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
         throw Error("empty response");
       }
       // FIXME: filter out types that bank/exchange don't have in common
-      let wireDetails = rci.wireInfo;
-      let filteredWireDetails: any = {};
-      for (let wireType in wireDetails) {
-        if (this.props.wt_types.findIndex((x) => x.toLowerCase() == 
wireType.toLowerCase()) < 0) {
+      const wireDetails = rci.wireInfo;
+      const filteredWireDetails: any = {};
+      for (const wireType in wireDetails) {
+        if (this.props.wt_types.findIndex((x) => x.toLowerCase() === 
wireType.toLowerCase()) < 0) {
           continue;
         }
-        let obj = Object.assign({}, wireDetails[wireType]);
+        const obj = Object.assign({}, wireDetails[wireType]);
         // The bank doesn't need to know about fees
         delete obj.fees;
         // Consequently the bank can't verify signatures anyway, so
@@ -563,15 +553,15 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
       }
       if (!rawResp.error) {
         const resp = CreateReserveResponse.checked(rawResp);
-        let q: {[name: string]: string|number} = {
-          wire_details: JSON.stringify(filteredWireDetails),
+        const q: {[name: string]: string|number} = {
+          amount_currency: amount.currency,
+          amount_fraction: amount.fraction,
+          amount_value: amount.value,
           exchange: resp.exchange,
           reserve_pub: resp.reservePub,
-          amount_value: amount.value,
-          amount_fraction: amount.fraction,
-          amount_currency: amount.currency,
+          wire_details: JSON.stringify(filteredWireDetails),
         };
-        let url = new URI(callback_url).addQuery(q);
+        const url = new URI(callback_url).addQuery(q);
         if (!url.is("absolute")) {
           throw Error("callback url is not absolute");
         }
@@ -582,7 +572,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
           i18n.str`Oops, something went wrong. The wallet responded with error 
status (${rawResp.error}).`);
       }
     };
-    chrome.runtime.sendMessage({type: 'create-reserve', detail: d}, cb);
+    chrome.runtime.sendMessage({type: "create-reserve", detail: d}, cb);
   }
 
   renderStatus(): any {
@@ -595,7 +585,7 @@ class ExchangeSelection extends 
ImplicitStateComponent<ExchangeSelectionProps> {
   }
 }
 
-export async function main() {
+async function main() {
   try {
     const url = new URI(document.location.href);
     const query: any = URI.parseQuery(url.query());
@@ -614,15 +604,15 @@ export async function main() {
       throw Error(i18n.str`Can't parse wire_types: ${e.message}`);
     }
 
-    let suggestedExchangeUrl = query.suggested_exchange_url;
-    let currencyRecord = await getCurrency(amount.currency);
+    const suggestedExchangeUrl = query.suggested_exchange_url;
+    const currencyRecord = await getCurrency(amount.currency);
 
-    let args = {
-      wt_types,
-      suggestedExchangeUrl,
-      callback_url,
+    const args = {
       amount,
+      callback_url,
       currencyRecord,
+      suggestedExchangeUrl,
+      wt_types,
     };
 
     ReactDOM.render(<ExchangeSelection {...args} />, document.getElementById(
diff --git a/src/webex/pages/error.tsx b/src/webex/pages/error.tsx
index f278bd22..829ea0c9 100644
--- a/src/webex/pages/error.tsx
+++ b/src/webex/pages/error.tsx
@@ -28,8 +28,6 @@ import * as React from "react";
 import * as ReactDOM from "react-dom";
 import URI = require("urijs");
 
-"use strict";
-
 interface ErrorProps {
   message: string;
 }
@@ -44,7 +42,7 @@ class ErrorView extends React.Component<ErrorProps, void> {
   }
 }
 
-export async function main() {
+async function main() {
   try {
     const url = new URI(document.location.href);
     const query: any = URI.parseQuery(url.query());
diff --git a/src/webex/pages/logs.tsx b/src/webex/pages/logs.tsx
index 0c533bfa..51f2cef3 100644
--- a/src/webex/pages/logs.tsx
+++ b/src/webex/pages/logs.tsx
@@ -20,7 +20,10 @@
  * @author Florian Dold
  */
 
-import {LogEntry, getLogs} from "../../logging";
+import {
+  LogEntry,
+  getLogs,
+} from "../../logging";
 
 import * as React from "react";
 import * as ReactDOM from "react-dom";
@@ -31,7 +34,7 @@ interface LogViewProps {
 
 class LogView extends React.Component<LogViewProps, void> {
   render(): JSX.Element {
-    let e = this.props.log;
+    const e = this.props.log;
     return (
       <div className="tree-item">
         <ul>
@@ -60,19 +63,19 @@ class Logs extends React.Component<any, LogsState> {
   }
 
   async update() {
-    let logs = await getLogs();
+    const logs = await getLogs();
     this.setState({logs});
   }
 
   render(): JSX.Element {
-    let logs = this.state.logs;
+    const logs = this.state.logs;
     if (!logs) {
       return <span>...</span>;
     }
     return (
       <div className="tree-item">
         Logs:
-        {logs.map(e => <LogView log={e} />)}
+        {logs.map((e) => <LogView log={e} />)}
       </div>
     );
   }
diff --git a/src/webex/pages/payback.tsx b/src/webex/pages/payback.tsx
index 7bcc581d..e10da7b0 100644
--- a/src/webex/pages/payback.tsx
+++ b/src/webex/pages/payback.tsx
@@ -21,25 +21,28 @@
  */
 
 
+/**
+ * Imports.
+ */
 import { amountToPretty, getTalerStampDate } from "../../helpers";
 import {
-  ExchangeRecord,
-  ExchangeForCurrencyRecord,
-  DenominationRecord,
   AuditorRecord,
-  CurrencyRecord,
-  ReserveRecord,
   CoinRecord,
-  PreCoinRecord,
+  CurrencyRecord,
   Denomination,
+  DenominationRecord,
+  ExchangeForCurrencyRecord,
+  ExchangeRecord,
+  PreCoinRecord,
+  ReserveRecord,
   WalletBalance,
 } from "../../types";
 
 import { ImplicitStateComponent, StateHolder } from "../components";
 import {
   getCurrencies,
-  updateCurrency,
   getPaybackReserves,
+  updateCurrency,
   withdrawPaybackReserve,
 } from "../wxApi";
 
@@ -47,10 +50,10 @@ import * as React from "react";
 import * as ReactDOM from "react-dom";
 
 class Payback extends ImplicitStateComponent<any> {
-  reserves: StateHolder<ReserveRecord[]|null> = this.makeState(null);
+  private reserves: StateHolder<ReserveRecord[]|null> = this.makeState(null);
   constructor() {
     super();
-    let port = chrome.runtime.connect();
+    const port = chrome.runtime.connect();
     port.onMessage.addListener((msg: any) => {
       if (msg.notify) {
         console.log("got notified");
@@ -61,25 +64,25 @@ class Payback extends ImplicitStateComponent<any> {
   }
 
   async update() {
-    let reserves = await getPaybackReserves();
+    const reserves = await getPaybackReserves();
     this.reserves(reserves);
   }
 
   withdrawPayback(pub: string) {
-    withdrawPaybackReserve(pub); 
+    withdrawPaybackReserve(pub);
   }
 
   render(): JSX.Element {
-    let reserves = this.reserves();
+    const reserves = this.reserves();
     if (!reserves) {
       return <span>loading ...</span>;
     }
-    if (reserves.length == 0) {
+    if (reserves.length === 0) {
       return <span>No reserves with payback available.</span>;
     }
     return (
       <div>
-        {reserves.map(r => (
+        {reserves.map((r) => (
           <div>
             <h2>Reserve for ${amountToPretty(r.current_amount!)}</h2>
             <ul>
@@ -93,7 +96,7 @@ class Payback extends ImplicitStateComponent<any> {
   }
 }
 
-export function main() {
+function main() {
   ReactDOM.render(<Payback />, document.getElementById("container")!);
 }
 
diff --git a/src/webex/wxApi.ts b/src/webex/wxApi.ts
index e5a50240..c120f34e 100644
--- a/src/webex/wxApi.ts
+++ b/src/webex/wxApi.ts
@@ -24,10 +24,13 @@
  */
 import {
   AmountJson,
+  CheckPayResult,
+  ConfirmPayResult,
   CoinRecord,
   CurrencyRecord,
   DenominationRecord,
   ExchangeRecord,
+  OfferRecord,
   PreCoinRecord,
   ReserveCreationInfo,
   ReserveRecord,
@@ -172,3 +175,26 @@ export async function refresh(coinPub: string): 
Promise<void> {
 export async function payback(coinPub: string): Promise<void> {
   return await callBackend("payback-coin", { coinPub });
 }
+
+/**
+ * Get an offer stored in the wallet by its offer id.
+ * Note that the numeric offer id is not to be confused with
+ * the string order_id from the contract terms.
+ */
+export async function getOffer(offerId: number) {
+  return await callBackend("get-offer", { offerId });
+}
+
+/**
+ * Check if payment is possible or already done.
+ */
+export async function checkPay(offer: OfferRecord): Promise<CheckPayResult> {
+  return await callBackend("check-pay", { offer });
+}
+
+/**
+ * Pay for an offer.
+ */
+export async function confirmPay(offer: OfferRecord): 
Promise<ConfirmPayResult> {
+  return await callBackend("confirm-pay", { offer });
+}
diff --git a/src/webex/wxBackend.ts b/src/webex/wxBackend.ts
index 2579bc31..c7aa34a9 100644
--- a/src/webex/wxBackend.ts
+++ b/src/webex/wxBackend.ts
@@ -35,12 +35,12 @@ import {
   AmountJson,
   Contract,
   Notifier,
+  OfferRecord,
 } from "../types";
 import {
   Badge,
   ConfirmReserveRequest,
   CreateReserveRequest,
-  OfferRecord,
   Stores,
   Wallet,
 } from "../wallet";

-- 
To stop receiving notification emails like this one, please contact
address@hidden



reply via email to

[Prev in Thread] Current Thread [Next in Thread]