less ad-hoc messaging, fix some lint warnings
This commit is contained in:
parent
d0e0c6baf2
commit
1c3346cd53
@ -27,6 +27,7 @@ import {
|
|||||||
AmountJson,
|
AmountJson,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
|
OfferRecord,
|
||||||
PayCoinInfo,
|
PayCoinInfo,
|
||||||
PaybackRequest,
|
PaybackRequest,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
@ -37,7 +38,6 @@ import {
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
CoinWithDenom,
|
CoinWithDenom,
|
||||||
OfferRecord,
|
|
||||||
} from "../wallet";
|
} from "../wallet";
|
||||||
|
|
||||||
import * as timer from "../timer";
|
import * as timer from "../timer";
|
||||||
|
@ -29,6 +29,7 @@ import {
|
|||||||
CoinRecord,
|
CoinRecord,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
|
OfferRecord,
|
||||||
PayCoinInfo,
|
PayCoinInfo,
|
||||||
PaybackRequest,
|
PaybackRequest,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
@ -39,7 +40,6 @@ import {
|
|||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import {
|
||||||
CoinWithDenom,
|
CoinWithDenom,
|
||||||
OfferRecord,
|
|
||||||
} from "../wallet";
|
} from "../wallet";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
46
src/i18n.tsx
46
src/i18n.tsx
@ -40,7 +40,7 @@ if (!strings[lang]) {
|
|||||||
console.log(`language ${lang} not found, defaulting to english`);
|
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.
|
* Internationalize a string template with arbitrary serialized values.
|
||||||
*/
|
*/
|
||||||
export function str(strings: TemplateStringsArray, ...values: any[]) {
|
export function str(strings: TemplateStringsArray, ...values: any[]) {
|
||||||
let str = toI18nString(strings);
|
const str = toI18nString(strings);
|
||||||
let tr = jed.translate(str).ifPlural(1, str).fetch(...values);
|
const tr = jed.translate(str).ifPlural(1, str).fetch(...values);
|
||||||
return tr;
|
return tr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ interface TranslateSwitchProps {
|
|||||||
|
|
||||||
function stringifyChildren(children: any): string {
|
function stringifyChildren(children: any): string {
|
||||||
let n = 1;
|
let n = 1;
|
||||||
let ss = React.Children.map(children, (c) => {
|
const ss = React.Children.map(children, (c) => {
|
||||||
if (typeof c === "string") {
|
if (typeof c === "string") {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
@ -113,23 +113,23 @@ interface TranslateProps {
|
|||||||
*/
|
*/
|
||||||
export class Translate extends React.Component<TranslateProps,void> {
|
export class Translate extends React.Component<TranslateProps,void> {
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let s = stringifyChildren(this.props.children);
|
const s = stringifyChildren(this.props.children);
|
||||||
let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 == 0);
|
const 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 childArray = React.Children.toArray(this.props.children!);
|
||||||
for (let i = 0; i < childArray.length - 1; ++i) {
|
for (let i = 0; i < childArray.length - 1; ++i) {
|
||||||
if ((typeof childArray[i]) == "string" && (typeof childArray[i+1]) == "string") {
|
if ((typeof childArray[i]) == "string" && (typeof childArray[i+1]) == "string") {
|
||||||
childArray[i+1] = (childArray[i] as string).concat(childArray[i+1] as string);
|
childArray[i+1] = (childArray[i] as string).concat(childArray[i+1] as string);
|
||||||
childArray.splice(i,1);
|
childArray.splice(i,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = [];
|
const result = [];
|
||||||
while (childArray.length > 0) {
|
while (childArray.length > 0) {
|
||||||
let x = childArray.shift();
|
const x = childArray.shift();
|
||||||
if (x === undefined) {
|
if (x === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (typeof x === "string") {
|
if (typeof x === "string") {
|
||||||
let t = tr.shift();
|
const t = tr.shift();
|
||||||
result.push(t);
|
result.push(t);
|
||||||
} else {
|
} else {
|
||||||
result.push(x);
|
result.push(x);
|
||||||
@ -159,7 +159,7 @@ export class TranslateSwitch extends React.Component<TranslateSwitchProps,void>{
|
|||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let singular: React.ReactElement<TranslationPluralProps> | undefined;
|
let singular: React.ReactElement<TranslationPluralProps> | undefined;
|
||||||
let plural: React.ReactElement<TranslationPluralProps> | undefined;
|
let plural: React.ReactElement<TranslationPluralProps> | undefined;
|
||||||
let children = this.props.children;
|
const children = this.props.children;
|
||||||
if (children) {
|
if (children) {
|
||||||
React.Children.forEach(children, (child: any) => {
|
React.Children.forEach(children, (child: any) => {
|
||||||
if (child.type == TranslatePlural) {
|
if (child.type == TranslatePlural) {
|
||||||
@ -192,23 +192,23 @@ interface TranslationPluralProps {
|
|||||||
*/
|
*/
|
||||||
export class TranslatePlural extends React.Component<TranslationPluralProps,void> {
|
export class TranslatePlural extends React.Component<TranslationPluralProps,void> {
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let s = stringifyChildren(this.props.children);
|
const s = stringifyChildren(this.props.children);
|
||||||
let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 == 0);
|
const 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 childArray = React.Children.toArray(this.props.children!);
|
||||||
for (let i = 0; i < childArray.length - 1; ++i) {
|
for (let i = 0; i < childArray.length - 1; ++i) {
|
||||||
if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == "string") {
|
if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == "string") {
|
||||||
childArray[i+i] = childArray[i] as string + childArray[i + 1] as string;
|
childArray[i+i] = childArray[i] as string + childArray[i + 1] as string;
|
||||||
childArray.splice(i,1);
|
childArray.splice(i,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = [];
|
const result = [];
|
||||||
while (childArray.length > 0) {
|
while (childArray.length > 0) {
|
||||||
let x = childArray.shift();
|
const x = childArray.shift();
|
||||||
if (x === undefined) {
|
if (x === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (typeof x === "string") {
|
if (typeof x === "string") {
|
||||||
let t = tr.shift();
|
const t = tr.shift();
|
||||||
result.push(t);
|
result.push(t);
|
||||||
} else {
|
} else {
|
||||||
result.push(x);
|
result.push(x);
|
||||||
@ -224,23 +224,23 @@ export class TranslatePlural extends React.Component<TranslationPluralProps,void
|
|||||||
*/
|
*/
|
||||||
export class TranslateSingular extends React.Component<TranslationPluralProps,void> {
|
export class TranslateSingular extends React.Component<TranslationPluralProps,void> {
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let s = stringifyChildren(this.props.children);
|
const s = stringifyChildren(this.props.children);
|
||||||
let tr = jed.ngettext(s, s, 1).split(/%(\d+)\$s/).filter((e: any, i: number) => i % 2 == 0);
|
const 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 childArray = React.Children.toArray(this.props.children!);
|
||||||
for (let i = 0; i < childArray.length - 1; ++i) {
|
for (let i = 0; i < childArray.length - 1; ++i) {
|
||||||
if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == "string") {
|
if ((typeof childArray[i]) == "string" && (typeof childArray[i + 1]) == "string") {
|
||||||
childArray[i+i] = childArray[i] as string + childArray[i + 1] as string;
|
childArray[i+i] = childArray[i] as string + childArray[i + 1] as string;
|
||||||
childArray.splice(i,1);
|
childArray.splice(i,1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let result = [];
|
const result = [];
|
||||||
while (childArray.length > 0) {
|
while (childArray.length > 0) {
|
||||||
let x = childArray.shift();
|
const x = childArray.shift();
|
||||||
if (x === undefined) {
|
if (x === undefined) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (typeof x === "string") {
|
if (typeof x === "string") {
|
||||||
let t = tr.shift();
|
const t = tr.shift();
|
||||||
result.push(t);
|
result.push(t);
|
||||||
} else {
|
} else {
|
||||||
result.push(x);
|
result.push(x);
|
||||||
|
52
src/types.ts
52
src/types.ts
@ -1074,6 +1074,51 @@ export class Contract {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offer record, stored in the wallet's database.
|
||||||
|
*/
|
||||||
|
@Checkable.Class()
|
||||||
|
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
|
* Wire fee for one wire method as stored in the
|
||||||
* wallet's database.
|
* wallet's database.
|
||||||
@ -1333,3 +1378,10 @@ export interface Notifier {
|
|||||||
export function mkAmount(value: number, fraction: number, currency: string): AmountJson {
|
export function mkAmount(value: number, fraction: number, currency: string): AmountJson {
|
||||||
return {value, fraction, currency};
|
return {value, fraction, currency};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Possible responses for checkPay.
|
||||||
|
*/
|
||||||
|
export type CheckPayResult = "paid" | "payment-possible" | "insufficient-balance";
|
||||||
|
|
||||||
|
export type ConfirmPayResult = "paid" | "insufficient-balance";
|
||||||
|
@ -50,9 +50,11 @@ import {
|
|||||||
Amounts,
|
Amounts,
|
||||||
Auditor,
|
Auditor,
|
||||||
AuditorRecord,
|
AuditorRecord,
|
||||||
|
CheckPayResult,
|
||||||
CoinPaySig,
|
CoinPaySig,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
CoinStatus,
|
CoinStatus,
|
||||||
|
ConfirmPayResult,
|
||||||
Contract,
|
Contract,
|
||||||
CreateReserveResponse,
|
CreateReserveResponse,
|
||||||
CurrencyRecord,
|
CurrencyRecord,
|
||||||
@ -63,6 +65,7 @@ import {
|
|||||||
ExchangeRecord,
|
ExchangeRecord,
|
||||||
ExchangeWireFeesRecord,
|
ExchangeWireFeesRecord,
|
||||||
Notifier,
|
Notifier,
|
||||||
|
OfferRecord,
|
||||||
PayCoinInfo,
|
PayCoinInfo,
|
||||||
PaybackConfirmation,
|
PaybackConfirmation,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
@ -271,48 +274,6 @@ export class ConfirmReserveRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Offer record, stored in the wallet's database.
|
|
||||||
*/
|
|
||||||
@Checkable.Class()
|
|
||||||
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.
|
* Activity history record.
|
||||||
*/
|
*/
|
||||||
@ -981,14 +942,14 @@ export class Wallet {
|
|||||||
* Add a contract to the wallet and sign coins,
|
* Add a contract to the wallet and sign coins,
|
||||||
* but do not send them yet.
|
* but do not send them yet.
|
||||||
*/
|
*/
|
||||||
async confirmPay(offer: OfferRecord): Promise<any> {
|
async confirmPay(offer: OfferRecord): Promise<ConfirmPayResult> {
|
||||||
console.log("executing confirmPay");
|
console.log("executing confirmPay");
|
||||||
|
|
||||||
const transaction = await this.q().get(Stores.transactions, offer.H_contract);
|
const transaction = await this.q().get(Stores.transactions, offer.H_contract);
|
||||||
|
|
||||||
if (transaction) {
|
if (transaction) {
|
||||||
// Already payed ...
|
// Already payed ...
|
||||||
return {};
|
return "paid";
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await this.getCoinsForPayment({
|
const res = await this.getCoinsForPayment({
|
||||||
@ -1007,29 +968,25 @@ export class Wallet {
|
|||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
console.log("not confirming payment, insufficient coins");
|
console.log("not confirming payment, insufficient coins");
|
||||||
return {
|
return "insufficient-balance";
|
||||||
error: "coins-insufficient",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
const {exchangeUrl, cds} = res;
|
const {exchangeUrl, cds} = res;
|
||||||
|
|
||||||
const ds = await this.cryptoApi.signDeposit(offer, cds);
|
const ds = await this.cryptoApi.signDeposit(offer, cds);
|
||||||
await this.recordConfirmPay(offer,
|
await this.recordConfirmPay(offer, ds, exchangeUrl);
|
||||||
ds,
|
return "paid";
|
||||||
exchangeUrl);
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a contract to the wallet and sign coins,
|
* Check if payment for an offer is possible, or if the offer has already
|
||||||
* but do not send them yet.
|
* been payed for.
|
||||||
*/
|
*/
|
||||||
async checkPay(offer: OfferRecord): Promise<any> {
|
async checkPay(offer: OfferRecord): Promise<CheckPayResult> {
|
||||||
// First check if we already payed for it.
|
// First check if we already payed for it.
|
||||||
const transaction = await this.q().get(Stores.transactions, offer.H_contract);
|
const transaction = await this.q().get(Stores.transactions, offer.H_contract);
|
||||||
if (transaction) {
|
if (transaction) {
|
||||||
return {isPayed: true};
|
return "insufficient-balance";
|
||||||
}
|
}
|
||||||
|
|
||||||
// If not already payed, check if we could pay for it.
|
// If not already payed, check if we could pay for it.
|
||||||
@ -1046,11 +1003,9 @@ export class Wallet {
|
|||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
console.log("not confirming payment, insufficient coins");
|
console.log("not confirming payment, insufficient coins");
|
||||||
return {
|
return "insufficient-balance";
|
||||||
error: "coins-insufficient",
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
return {isPayed: false};
|
return "payment-possible";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,11 +24,15 @@
|
|||||||
* Imports.
|
* Imports.
|
||||||
*/
|
*/
|
||||||
import * as i18n from "../../i18n";
|
import * as i18n from "../../i18n";
|
||||||
import { Contract, AmountJson, ExchangeRecord } from "../../types";
|
import {
|
||||||
import { OfferRecord } from "../../wallet";
|
AmountJson,
|
||||||
|
Contract,
|
||||||
|
ExchangeRecord,
|
||||||
|
OfferRecord,
|
||||||
|
} from "../../types";
|
||||||
|
|
||||||
import { renderContract } from "../renderHtml";
|
import { renderContract } from "../renderHtml";
|
||||||
import { getExchanges } from "../wxApi";
|
import * as wxApi from "../wxApi";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
@ -125,39 +129,21 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
async update() {
|
||||||
let offer = await this.getOffer();
|
let offer = await wxApi.getOffer(this.props.offerId);
|
||||||
this.setState({offer} as any);
|
this.setState({offer} as any);
|
||||||
this.checkPayment();
|
this.checkPayment();
|
||||||
let exchanges = await getExchanges();
|
let exchanges = await wxApi.getExchanges();
|
||||||
this.setState({exchanges} as any);
|
this.setState({exchanges} as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
getOffer(): Promise<OfferRecord> {
|
async checkPayment() {
|
||||||
return new Promise<OfferRecord>((resolve, reject) => {
|
let offer = this.state.offer;
|
||||||
let msg = {
|
if (!offer) {
|
||||||
type: 'get-offer',
|
return;
|
||||||
detail: {
|
|
||||||
offerId: this.props.offerId
|
|
||||||
}
|
|
||||||
};
|
|
||||||
chrome.runtime.sendMessage(msg, (resp) => {
|
|
||||||
resolve(resp);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
const payStatus = await wxApi.checkPay(offer);
|
||||||
|
|
||||||
checkPayment() {
|
if (payStatus === "insufficient-balance") {
|
||||||
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 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.`;
|
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) {
|
if (this.state.exchanges && this.state.offer) {
|
||||||
@ -171,39 +157,28 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
|||||||
} else {
|
} else {
|
||||||
this.setState({error: msgInsufficient});
|
this.setState({error: msgInsufficient});
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
this.setState({error: `Error: ${resp.error}`});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
this.setState({payDisabled: true});
|
this.setState({payDisabled: true});
|
||||||
} else {
|
} else {
|
||||||
this.setState({payDisabled: false, error: null});
|
this.setState({payDisabled: false, error: null});
|
||||||
}
|
}
|
||||||
this.setState({} as any);
|
|
||||||
window.setTimeout(() => this.checkPayment(), 500);
|
window.setTimeout(() => this.checkPayment(), 500);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
doPayment() {
|
async doPayment() {
|
||||||
let d = {offer: this.state.offer};
|
let offer = this.state.offer;
|
||||||
chrome.runtime.sendMessage({type: 'confirm-pay', detail: d}, (resp) => {
|
if (!offer) {
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
let c = d.offer!.contract;
|
const payStatus = await wxApi.confirmPay(offer);
|
||||||
console.log("contract", c);
|
switch (payStatus) {
|
||||||
document.location.href = c.fulfillment_url;
|
case "insufficient-balance":
|
||||||
});
|
this.checkPayment();
|
||||||
|
return;
|
||||||
|
case "paid":
|
||||||
|
console.log("contract", offer.contract);
|
||||||
|
document.location.href = offer.contract.fulfillment_url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,15 +23,23 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {amountToPretty, canonicalizeBaseUrl} from "../../helpers";
|
import {amountToPretty, canonicalizeBaseUrl} from "../../helpers";
|
||||||
import {
|
|
||||||
AmountJson, CreateReserveResponse,
|
|
||||||
ReserveCreationInfo, Amounts,
|
|
||||||
Denomination, DenominationRecord, CurrencyRecord
|
|
||||||
} from "../../types";
|
|
||||||
import * as i18n from "../../i18n";
|
import * as i18n from "../../i18n";
|
||||||
|
import {
|
||||||
|
AmountJson,
|
||||||
|
Amounts,
|
||||||
|
CreateReserveResponse,
|
||||||
|
CurrencyRecord,
|
||||||
|
Denomination,
|
||||||
|
DenominationRecord,
|
||||||
|
ReserveCreationInfo,
|
||||||
|
} from "../../types";
|
||||||
|
|
||||||
import {getReserveCreationInfo, getCurrency, getExchangeInfo} from "../wxApi";
|
|
||||||
import {ImplicitStateComponent, StateHolder} from "../components";
|
import {ImplicitStateComponent, StateHolder} from "../components";
|
||||||
|
import {
|
||||||
|
getCurrency,
|
||||||
|
getExchangeInfo,
|
||||||
|
getReserveCreationInfo,
|
||||||
|
} from "../wxApi";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
@ -46,8 +54,8 @@ function delay<T>(delayMs: number, value: T): Promise<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class EventTrigger {
|
class EventTrigger {
|
||||||
triggerResolve: any;
|
private triggerResolve: any;
|
||||||
triggerPromise: Promise<boolean>;
|
private triggerPromise: Promise<boolean>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.reset();
|
this.reset();
|
||||||
@ -86,11 +94,11 @@ class Collapsible extends React.Component<CollapsibleProps, CollapsibleState> {
|
|||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const doOpen = (e: any) => {
|
const doOpen = (e: any) => {
|
||||||
this.setState({collapsed: false})
|
this.setState({collapsed: false});
|
||||||
e.preventDefault()
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
const doClose = (e: any) => {
|
const doClose = (e: any) => {
|
||||||
this.setState({collapsed: true})
|
this.setState({collapsed: true});
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
};
|
};
|
||||||
if (this.state.collapsed) {
|
if (this.state.collapsed) {
|
||||||
@ -113,7 +121,7 @@ function renderAuditorDetails(rci: ReserveCreationInfo|null) {
|
|||||||
</p>
|
</p>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (rci.exchangeInfo.auditors.length == 0) {
|
if (rci.exchangeInfo.auditors.length === 0) {
|
||||||
return (
|
return (
|
||||||
<p>
|
<p>
|
||||||
The exchange is not audited by any auditors.
|
The exchange is not audited by any auditors.
|
||||||
@ -122,7 +130,7 @@ function renderAuditorDetails(rci: ReserveCreationInfo|null) {
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{rci.exchangeInfo.auditors.map(a => (
|
{rci.exchangeInfo.auditors.map((a) => (
|
||||||
<h3>Auditor {a.url}</h3>
|
<h3>Auditor {a.url}</h3>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@ -138,14 +146,14 @@ function renderReserveCreationDetails(rci: ReserveCreationInfo|null) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let denoms = rci.selectedDenoms;
|
const denoms = rci.selectedDenoms;
|
||||||
|
|
||||||
let countByPub: {[s: string]: number} = {};
|
const countByPub: {[s: string]: number} = {};
|
||||||
let uniq: DenominationRecord[] = [];
|
const uniq: DenominationRecord[] = [];
|
||||||
|
|
||||||
denoms.forEach((x: DenominationRecord) => {
|
denoms.forEach((x: DenominationRecord) => {
|
||||||
let c = countByPub[x.denomPub] || 0;
|
let c = countByPub[x.denomPub] || 0;
|
||||||
if (c == 0) {
|
if (c === 0) {
|
||||||
uniq.push(x);
|
uniq.push(x);
|
||||||
}
|
}
|
||||||
c += 1;
|
c += 1;
|
||||||
@ -177,19 +185,19 @@ function renderReserveCreationDetails(rci: ReserveCreationInfo|null) {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>,
|
</thead>,
|
||||||
<tbody>
|
<tbody>
|
||||||
{rci!.wireFees.feesForType[s].map(f => (
|
{rci!.wireFees.feesForType[s].map((f) => (
|
||||||
<tr>
|
<tr>
|
||||||
<td>{moment.unix(f.endStamp).format("llll")}</td>
|
<td>{moment.unix(f.endStamp).format("llll")}</td>
|
||||||
<td>{amountToPretty(f.wireFee)}</td>
|
<td>{amountToPretty(f.wireFee)}</td>
|
||||||
<td>{amountToPretty(f.closingFee)}</td>
|
<td>{amountToPretty(f.closingFee)}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
let withdrawFeeStr = amountToPretty(rci.withdrawFee);
|
const withdrawFeeStr = amountToPretty(rci.withdrawFee);
|
||||||
let overheadStr = amountToPretty(rci.overhead);
|
const overheadStr = amountToPretty(rci.overhead);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<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 {
|
function WithdrawFee(props: {reserveCreationInfo: ReserveCreationInfo|null}): JSX.Element {
|
||||||
if (props.reserveCreationInfo) {
|
if (props.reserveCreationInfo) {
|
||||||
let {overhead, withdrawFee} = props.reserveCreationInfo;
|
const {overhead, withdrawFee} = props.reserveCreationInfo;
|
||||||
let totalCost = Amounts.add(overhead, withdrawFee).amount;
|
const totalCost = Amounts.add(overhead, withdrawFee).amount;
|
||||||
return <p>{i18n.str`Withdraw fees:`} {amountToPretty(totalCost)}</p>;
|
return <p>{i18n.str`Withdraw fees:`} {amountToPretty(totalCost)}</p>;
|
||||||
}
|
}
|
||||||
return <p />;
|
return <p />;
|
||||||
@ -263,10 +253,10 @@ interface ManualSelectionProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
|
class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
|
||||||
url: StateHolder<string> = this.makeState("");
|
private url: StateHolder<string> = this.makeState("");
|
||||||
errorMessage: StateHolder<string|null> = this.makeState(null);
|
private errorMessage: StateHolder<string|null> = this.makeState(null);
|
||||||
isOkay: StateHolder<boolean> = this.makeState(false);
|
private isOkay: StateHolder<boolean> = this.makeState(false);
|
||||||
updateEvent = new EventTrigger();
|
private updateEvent = new EventTrigger();
|
||||||
constructor(p: ManualSelectionProps) {
|
constructor(p: ManualSelectionProps) {
|
||||||
super(p);
|
super(p);
|
||||||
this.url(p.initialUrl);
|
this.url(p.initialUrl);
|
||||||
@ -300,23 +290,23 @@ class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
|
|||||||
if (!this.url()) {
|
if (!this.url()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let parsedUrl = new URI(this.url()!);
|
const parsedUrl = new URI(this.url()!);
|
||||||
if (parsedUrl.is("relative")) {
|
if (parsedUrl.is("relative")) {
|
||||||
this.errorMessage(i18n.str`Error: URL may not be relative`);
|
this.errorMessage(i18n.str`Error: URL may not be relative`);
|
||||||
this.isOkay(false);
|
this.isOkay(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let url = canonicalizeBaseUrl(this.url()!);
|
const url = canonicalizeBaseUrl(this.url()!);
|
||||||
let r = await getExchangeInfo(url)
|
const r = await getExchangeInfo(url);
|
||||||
console.log("getExchangeInfo returned")
|
console.log("getExchangeInfo returned");
|
||||||
this.isOkay(true);
|
this.isOkay(true);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("got error", e);
|
console.log("got error", e);
|
||||||
if (e.hasOwnProperty("httpStatus")) {
|
if (e.hasOwnProperty("httpStatus")) {
|
||||||
this.errorMessage(`Error: request failed with status ${e.httpStatus}`);
|
this.errorMessage(`Error: request failed with status ${e.httpStatus}`);
|
||||||
} else if (e.hasOwnProperty("errorResponse")) {
|
} else if (e.hasOwnProperty("errorResponse")) {
|
||||||
let resp = e.errorResponse;
|
const resp = e.errorResponse;
|
||||||
this.errorMessage(`Error: ${resp.error} (${resp.hint})`);
|
this.errorMessage(`Error: ${resp.error} (${resp.hint})`);
|
||||||
} else {
|
} else {
|
||||||
this.errorMessage("invalid exchange URL");
|
this.errorMessage("invalid exchange URL");
|
||||||
@ -329,7 +319,7 @@ class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
|
|||||||
this.errorMessage(null);
|
this.errorMessage(null);
|
||||||
this.isOkay(false);
|
this.isOkay(false);
|
||||||
this.updateEvent.trigger();
|
this.updateEvent.trigger();
|
||||||
let waited = await this.updateEvent.wait(200);
|
const waited = await this.updateEvent.wait(200);
|
||||||
if (waited) {
|
if (waited) {
|
||||||
// Run the actual update if nobody else preempted us.
|
// Run the actual update if nobody else preempted us.
|
||||||
this.update();
|
this.update();
|
||||||
@ -339,24 +329,24 @@ class ManualSelection extends ImplicitStateComponent<ManualSelectionProps> {
|
|||||||
|
|
||||||
|
|
||||||
class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
||||||
statusString: StateHolder<string|null> = this.makeState(null);
|
private statusString: StateHolder<string|null> = this.makeState(null);
|
||||||
reserveCreationInfo: StateHolder<ReserveCreationInfo|null> = this.makeState(
|
private reserveCreationInfo: StateHolder<ReserveCreationInfo|null> = this.makeState(
|
||||||
null);
|
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) {
|
constructor(props: ExchangeSelectionProps) {
|
||||||
super(props);
|
super(props);
|
||||||
let prefilledExchangesUrls = [];
|
const prefilledExchangesUrls = [];
|
||||||
if (props.currencyRecord) {
|
if (props.currencyRecord) {
|
||||||
let exchanges = props.currencyRecord.exchanges.map((x) => x.baseUrl);
|
const exchanges = props.currencyRecord.exchanges.map((x) => x.baseUrl);
|
||||||
prefilledExchangesUrls.push(...exchanges);
|
prefilledExchangesUrls.push(...exchanges);
|
||||||
}
|
}
|
||||||
if (props.suggestedExchangeUrl) {
|
if (props.suggestedExchangeUrl) {
|
||||||
prefilledExchangesUrls.push(props.suggestedExchangeUrl);
|
prefilledExchangesUrls.push(props.suggestedExchangeUrl);
|
||||||
}
|
}
|
||||||
if (prefilledExchangesUrls.length != 0) {
|
if (prefilledExchangesUrls.length !== 0) {
|
||||||
this.url(prefilledExchangesUrls[0]);
|
this.url(prefilledExchangesUrls[0]);
|
||||||
this.forceReserveUpdate();
|
this.forceReserveUpdate();
|
||||||
} else {
|
} else {
|
||||||
@ -365,9 +355,9 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderFeeStatus() {
|
renderFeeStatus() {
|
||||||
let rci = this.reserveCreationInfo();
|
const rci = this.reserveCreationInfo();
|
||||||
if (rci) {
|
if (rci) {
|
||||||
let totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
|
const totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
|
||||||
let trustMessage;
|
let trustMessage;
|
||||||
if (rci.isTrusted) {
|
if (rci.isTrusted) {
|
||||||
trustMessage = (
|
trustMessage = (
|
||||||
@ -404,7 +394,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.url() && !this.statusString()) {
|
if (this.url() && !this.statusString()) {
|
||||||
let shortName = new URI(this.url()!).host();
|
const shortName = new URI(this.url()!).host();
|
||||||
return (
|
return (
|
||||||
<i18n.Translate wrap="p">
|
<i18n.Translate wrap="p">
|
||||||
Waiting for a response from
|
Waiting for a response from
|
||||||
@ -432,7 +422,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
<div>
|
<div>
|
||||||
{this.renderFeeStatus()}
|
{this.renderFeeStatus()}
|
||||||
<button className="pure-button button-success"
|
<button className="pure-button button-success"
|
||||||
disabled={this.reserveCreationInfo() == null}
|
disabled={this.reserveCreationInfo() === null}
|
||||||
onClick={() => this.confirmReserve()}>
|
onClick={() => this.confirmReserve()}>
|
||||||
{i18n.str`Accept fees and withdraw`}
|
{i18n.str`Accept fees and withdraw`}
|
||||||
</button>
|
</button>
|
||||||
@ -460,7 +450,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderSelect() {
|
renderSelect() {
|
||||||
let exchanges = (this.props.currencyRecord && this.props.currencyRecord.exchanges) || [];
|
const exchanges = (this.props.currencyRecord && this.props.currencyRecord.exchanges) || [];
|
||||||
console.log(exchanges);
|
console.log(exchanges);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@ -478,7 +468,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
{exchanges.length > 0 && (
|
{exchanges.length > 0 && (
|
||||||
<div>
|
<div>
|
||||||
<h2>Known Exchanges</h2>
|
<h2>Known Exchanges</h2>
|
||||||
{exchanges.map(e => (
|
{exchanges.map((e) => (
|
||||||
<button className="pure-button button-success" onClick={() => this.select(e.baseUrl)}>
|
<button className="pure-button button-success" onClick={() => this.select(e.baseUrl)}>
|
||||||
Select <strong>{e.baseUrl}</strong>
|
Select <strong>{e.baseUrl}</strong>
|
||||||
</button>
|
</button>
|
||||||
@ -519,8 +509,8 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
async forceReserveUpdate() {
|
async forceReserveUpdate() {
|
||||||
this.reserveCreationInfo(null);
|
this.reserveCreationInfo(null);
|
||||||
try {
|
try {
|
||||||
let url = canonicalizeBaseUrl(this.url()!);
|
const url = canonicalizeBaseUrl(this.url()!);
|
||||||
let r = await getReserveCreationInfo(url,
|
const r = await getReserveCreationInfo(url,
|
||||||
this.props.amount);
|
this.props.amount);
|
||||||
console.log("get exchange info resolved");
|
console.log("get exchange info resolved");
|
||||||
this.reserveCreationInfo(r);
|
this.reserveCreationInfo(r);
|
||||||
@ -530,7 +520,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
if (e.hasOwnProperty("httpStatus")) {
|
if (e.hasOwnProperty("httpStatus")) {
|
||||||
this.statusString(`Error: request failed with status ${e.httpStatus}`);
|
this.statusString(`Error: request failed with status ${e.httpStatus}`);
|
||||||
} else if (e.hasOwnProperty("errorResponse")) {
|
} else if (e.hasOwnProperty("errorResponse")) {
|
||||||
let resp = e.errorResponse;
|
const resp = e.errorResponse;
|
||||||
this.statusString(`Error: ${resp.error} (${resp.hint})`);
|
this.statusString(`Error: ${resp.error} (${resp.hint})`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -546,13 +536,13 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
throw Error("empty response");
|
throw Error("empty response");
|
||||||
}
|
}
|
||||||
// FIXME: filter out types that bank/exchange don't have in common
|
// FIXME: filter out types that bank/exchange don't have in common
|
||||||
let wireDetails = rci.wireInfo;
|
const wireDetails = rci.wireInfo;
|
||||||
let filteredWireDetails: any = {};
|
const filteredWireDetails: any = {};
|
||||||
for (let wireType in wireDetails) {
|
for (const wireType in wireDetails) {
|
||||||
if (this.props.wt_types.findIndex((x) => x.toLowerCase() == wireType.toLowerCase()) < 0) {
|
if (this.props.wt_types.findIndex((x) => x.toLowerCase() === wireType.toLowerCase()) < 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let obj = Object.assign({}, wireDetails[wireType]);
|
const obj = Object.assign({}, wireDetails[wireType]);
|
||||||
// The bank doesn't need to know about fees
|
// The bank doesn't need to know about fees
|
||||||
delete obj.fees;
|
delete obj.fees;
|
||||||
// Consequently the bank can't verify signatures anyway, so
|
// Consequently the bank can't verify signatures anyway, so
|
||||||
@ -563,15 +553,15 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
}
|
}
|
||||||
if (!rawResp.error) {
|
if (!rawResp.error) {
|
||||||
const resp = CreateReserveResponse.checked(rawResp);
|
const resp = CreateReserveResponse.checked(rawResp);
|
||||||
let q: {[name: string]: string|number} = {
|
const q: {[name: string]: string|number} = {
|
||||||
wire_details: JSON.stringify(filteredWireDetails),
|
amount_currency: amount.currency,
|
||||||
|
amount_fraction: amount.fraction,
|
||||||
|
amount_value: amount.value,
|
||||||
exchange: resp.exchange,
|
exchange: resp.exchange,
|
||||||
reserve_pub: resp.reservePub,
|
reserve_pub: resp.reservePub,
|
||||||
amount_value: amount.value,
|
wire_details: JSON.stringify(filteredWireDetails),
|
||||||
amount_fraction: amount.fraction,
|
|
||||||
amount_currency: amount.currency,
|
|
||||||
};
|
};
|
||||||
let url = new URI(callback_url).addQuery(q);
|
const url = new URI(callback_url).addQuery(q);
|
||||||
if (!url.is("absolute")) {
|
if (!url.is("absolute")) {
|
||||||
throw Error("callback url is not 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}).`);
|
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 {
|
renderStatus(): any {
|
||||||
@ -595,7 +585,7 @@ class ExchangeSelection extends ImplicitStateComponent<ExchangeSelectionProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
const url = new URI(document.location.href);
|
const url = new URI(document.location.href);
|
||||||
const query: any = URI.parseQuery(url.query());
|
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}`);
|
throw Error(i18n.str`Can't parse wire_types: ${e.message}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
let suggestedExchangeUrl = query.suggested_exchange_url;
|
const suggestedExchangeUrl = query.suggested_exchange_url;
|
||||||
let currencyRecord = await getCurrency(amount.currency);
|
const currencyRecord = await getCurrency(amount.currency);
|
||||||
|
|
||||||
let args = {
|
const args = {
|
||||||
wt_types,
|
|
||||||
suggestedExchangeUrl,
|
|
||||||
callback_url,
|
|
||||||
amount,
|
amount,
|
||||||
|
callback_url,
|
||||||
currencyRecord,
|
currencyRecord,
|
||||||
|
suggestedExchangeUrl,
|
||||||
|
wt_types,
|
||||||
};
|
};
|
||||||
|
|
||||||
ReactDOM.render(<ExchangeSelection {...args} />, document.getElementById(
|
ReactDOM.render(<ExchangeSelection {...args} />, document.getElementById(
|
||||||
|
@ -28,8 +28,6 @@ import * as React from "react";
|
|||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
import URI = require("urijs");
|
import URI = require("urijs");
|
||||||
|
|
||||||
"use strict";
|
|
||||||
|
|
||||||
interface ErrorProps {
|
interface ErrorProps {
|
||||||
message: string;
|
message: string;
|
||||||
}
|
}
|
||||||
@ -44,7 +42,7 @@ class ErrorView extends React.Component<ErrorProps, void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
const url = new URI(document.location.href);
|
const url = new URI(document.location.href);
|
||||||
const query: any = URI.parseQuery(url.query());
|
const query: any = URI.parseQuery(url.query());
|
||||||
|
@ -20,7 +20,10 @@
|
|||||||
* @author Florian Dold
|
* @author Florian Dold
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {LogEntry, getLogs} from "../../logging";
|
import {
|
||||||
|
LogEntry,
|
||||||
|
getLogs,
|
||||||
|
} from "../../logging";
|
||||||
|
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
@ -31,7 +34,7 @@ interface LogViewProps {
|
|||||||
|
|
||||||
class LogView extends React.Component<LogViewProps, void> {
|
class LogView extends React.Component<LogViewProps, void> {
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let e = this.props.log;
|
const e = this.props.log;
|
||||||
return (
|
return (
|
||||||
<div className="tree-item">
|
<div className="tree-item">
|
||||||
<ul>
|
<ul>
|
||||||
@ -60,19 +63,19 @@ class Logs extends React.Component<any, LogsState> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
async update() {
|
||||||
let logs = await getLogs();
|
const logs = await getLogs();
|
||||||
this.setState({logs});
|
this.setState({logs});
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let logs = this.state.logs;
|
const logs = this.state.logs;
|
||||||
if (!logs) {
|
if (!logs) {
|
||||||
return <span>...</span>;
|
return <span>...</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="tree-item">
|
<div className="tree-item">
|
||||||
Logs:
|
Logs:
|
||||||
{logs.map(e => <LogView log={e} />)}
|
{logs.map((e) => <LogView log={e} />)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -21,25 +21,28 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports.
|
||||||
|
*/
|
||||||
import { amountToPretty, getTalerStampDate } from "../../helpers";
|
import { amountToPretty, getTalerStampDate } from "../../helpers";
|
||||||
import {
|
import {
|
||||||
ExchangeRecord,
|
|
||||||
ExchangeForCurrencyRecord,
|
|
||||||
DenominationRecord,
|
|
||||||
AuditorRecord,
|
AuditorRecord,
|
||||||
CurrencyRecord,
|
|
||||||
ReserveRecord,
|
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
PreCoinRecord,
|
CurrencyRecord,
|
||||||
Denomination,
|
Denomination,
|
||||||
|
DenominationRecord,
|
||||||
|
ExchangeForCurrencyRecord,
|
||||||
|
ExchangeRecord,
|
||||||
|
PreCoinRecord,
|
||||||
|
ReserveRecord,
|
||||||
WalletBalance,
|
WalletBalance,
|
||||||
} from "../../types";
|
} from "../../types";
|
||||||
|
|
||||||
import { ImplicitStateComponent, StateHolder } from "../components";
|
import { ImplicitStateComponent, StateHolder } from "../components";
|
||||||
import {
|
import {
|
||||||
getCurrencies,
|
getCurrencies,
|
||||||
updateCurrency,
|
|
||||||
getPaybackReserves,
|
getPaybackReserves,
|
||||||
|
updateCurrency,
|
||||||
withdrawPaybackReserve,
|
withdrawPaybackReserve,
|
||||||
} from "../wxApi";
|
} from "../wxApi";
|
||||||
|
|
||||||
@ -47,10 +50,10 @@ import * as React from "react";
|
|||||||
import * as ReactDOM from "react-dom";
|
import * as ReactDOM from "react-dom";
|
||||||
|
|
||||||
class Payback extends ImplicitStateComponent<any> {
|
class Payback extends ImplicitStateComponent<any> {
|
||||||
reserves: StateHolder<ReserveRecord[]|null> = this.makeState(null);
|
private reserves: StateHolder<ReserveRecord[]|null> = this.makeState(null);
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
let port = chrome.runtime.connect();
|
const port = chrome.runtime.connect();
|
||||||
port.onMessage.addListener((msg: any) => {
|
port.onMessage.addListener((msg: any) => {
|
||||||
if (msg.notify) {
|
if (msg.notify) {
|
||||||
console.log("got notified");
|
console.log("got notified");
|
||||||
@ -61,7 +64,7 @@ class Payback extends ImplicitStateComponent<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async update() {
|
async update() {
|
||||||
let reserves = await getPaybackReserves();
|
const reserves = await getPaybackReserves();
|
||||||
this.reserves(reserves);
|
this.reserves(reserves);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,16 +73,16 @@ class Payback extends ImplicitStateComponent<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render(): JSX.Element {
|
render(): JSX.Element {
|
||||||
let reserves = this.reserves();
|
const reserves = this.reserves();
|
||||||
if (!reserves) {
|
if (!reserves) {
|
||||||
return <span>loading ...</span>;
|
return <span>loading ...</span>;
|
||||||
}
|
}
|
||||||
if (reserves.length == 0) {
|
if (reserves.length === 0) {
|
||||||
return <span>No reserves with payback available.</span>;
|
return <span>No reserves with payback available.</span>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{reserves.map(r => (
|
{reserves.map((r) => (
|
||||||
<div>
|
<div>
|
||||||
<h2>Reserve for ${amountToPretty(r.current_amount!)}</h2>
|
<h2>Reserve for ${amountToPretty(r.current_amount!)}</h2>
|
||||||
<ul>
|
<ul>
|
||||||
@ -93,7 +96,7 @@ class Payback extends ImplicitStateComponent<any> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function main() {
|
function main() {
|
||||||
ReactDOM.render(<Payback />, document.getElementById("container")!);
|
ReactDOM.render(<Payback />, document.getElementById("container")!);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,10 +24,13 @@
|
|||||||
*/
|
*/
|
||||||
import {
|
import {
|
||||||
AmountJson,
|
AmountJson,
|
||||||
|
CheckPayResult,
|
||||||
|
ConfirmPayResult,
|
||||||
CoinRecord,
|
CoinRecord,
|
||||||
CurrencyRecord,
|
CurrencyRecord,
|
||||||
DenominationRecord,
|
DenominationRecord,
|
||||||
ExchangeRecord,
|
ExchangeRecord,
|
||||||
|
OfferRecord,
|
||||||
PreCoinRecord,
|
PreCoinRecord,
|
||||||
ReserveCreationInfo,
|
ReserveCreationInfo,
|
||||||
ReserveRecord,
|
ReserveRecord,
|
||||||
@ -172,3 +175,26 @@ export async function refresh(coinPub: string): Promise<void> {
|
|||||||
export async function payback(coinPub: string): Promise<void> {
|
export async function payback(coinPub: string): Promise<void> {
|
||||||
return await callBackend("payback-coin", { coinPub });
|
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 });
|
||||||
|
}
|
||||||
|
@ -35,12 +35,12 @@ import {
|
|||||||
AmountJson,
|
AmountJson,
|
||||||
Contract,
|
Contract,
|
||||||
Notifier,
|
Notifier,
|
||||||
|
OfferRecord,
|
||||||
} from "../types";
|
} from "../types";
|
||||||
import {
|
import {
|
||||||
Badge,
|
Badge,
|
||||||
ConfirmReserveRequest,
|
ConfirmReserveRequest,
|
||||||
CreateReserveRequest,
|
CreateReserveRequest,
|
||||||
OfferRecord,
|
|
||||||
Stores,
|
Stores,
|
||||||
Wallet,
|
Wallet,
|
||||||
} from "../wallet";
|
} from "../wallet";
|
||||||
|
Loading…
Reference in New Issue
Block a user