fix small react issues
This commit is contained in:
parent
b2128609ac
commit
eb84d5747a
@ -102,6 +102,25 @@ namespace TalerNotify {
|
||||
});
|
||||
}
|
||||
|
||||
function saveOffer(offer: any): Promise<number> {
|
||||
const walletMsg = {
|
||||
type: "save-offer",
|
||||
detail: {
|
||||
offer: {
|
||||
contract: offer.contract,
|
||||
merchant_sig: offer.merchant_sig,
|
||||
H_contract: offer.H_contract,
|
||||
offer_time: new Date().getTime() / 1000
|
||||
},
|
||||
},
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.runtime.sendMessage(walletMsg, (resp: any) => {
|
||||
resolve(resp);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
chrome.runtime.sendMessage({type: "get-tab-cookie"}, (resp) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
@ -270,12 +289,12 @@ namespace TalerNotify {
|
||||
}
|
||||
};
|
||||
await putHistory(historyEntry);
|
||||
let offerId = await saveOffer(offer);
|
||||
|
||||
const uri = URI(chrome.extension.getURL(
|
||||
"pages/confirm-contract.html"));
|
||||
const params = {
|
||||
offer: JSON.stringify(offer),
|
||||
merchantPageUrl: document.location.href,
|
||||
offerId: offerId.toString(),
|
||||
};
|
||||
const target = uri.query(params).href();
|
||||
if (msg.replace_navigation === true) {
|
||||
|
18525
lib/vendor/react-dom.js
vendored
18525
lib/vendor/react-dom.js
vendored
File diff suppressed because it is too large
Load Diff
1
lib/vendor/react-dom.js
vendored
Symbolic link
1
lib/vendor/react-dom.js
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
react-dom.min.js
|
3783
lib/vendor/react.js
vendored
3783
lib/vendor/react.js
vendored
File diff suppressed because it is too large
Load Diff
1
lib/vendor/react.js
vendored
Symbolic link
1
lib/vendor/react.js
vendored
Symbolic link
@ -0,0 +1 @@
|
||||
react.min.js
|
@ -26,7 +26,7 @@ import {IExchangeInfo} from "./types";
|
||||
*/
|
||||
|
||||
const DB_NAME = "taler";
|
||||
const DB_VERSION = 10;
|
||||
const DB_VERSION = 11;
|
||||
|
||||
import {Stores} from "./wallet";
|
||||
import {Store, Index} from "./query";
|
||||
@ -114,4 +114,4 @@ export function exportDb(db: IDBDatabase): Promise<any> {
|
||||
|
||||
export function deleteDb() {
|
||||
indexedDB.deleteDatabase(DB_NAME);
|
||||
}
|
||||
}
|
||||
|
@ -423,6 +423,22 @@ export class QueryRoot implements PromiseLike<void> {
|
||||
}
|
||||
|
||||
|
||||
putWithResult<T>(store: Store<T>, val: T): Promise<IDBValidKey> {
|
||||
const {resolve, promise} = openPromise();
|
||||
let doPutWithResult = (tx: IDBTransaction) => {
|
||||
let req = tx.objectStore(store.name).put(val);
|
||||
req.onsuccess = () => {
|
||||
resolve(req.result);
|
||||
}
|
||||
this.scheduleFinish();
|
||||
};
|
||||
this.addWork(doPutWithResult, store.name, true);
|
||||
return Promise.resolve()
|
||||
.then(() => this.finish())
|
||||
.then(() => promise);
|
||||
}
|
||||
|
||||
|
||||
mutate<T>(store: Store<T>, key: any, f: (v: T) => T): QueryRoot {
|
||||
let doPut = (tx: IDBTransaction) => {
|
||||
let reqGet = tx.objectStore(store.name).get(key);
|
||||
|
@ -34,15 +34,15 @@ export function renderContract(contract: Contract): JSX.Element {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>{
|
||||
i18n.parts`${merchantName}
|
||||
wants to enter a contract over ${amount}
|
||||
with you.`}
|
||||
<p>
|
||||
The merchant {merchantName}
|
||||
wants to enter a contract over {amount}{" "}
|
||||
with you.
|
||||
</p>
|
||||
<p>{i18n`You are about to purchase:`}</p>
|
||||
<ul>
|
||||
{contract.products.map(
|
||||
(p: any) => (<li>{`${p.description}: ${prettyAmount(p.price)}`}</li>))
|
||||
(p: any, i: number) => (<li key={i}>{`${p.description}: ${prettyAmount(p.price)}`}</li>))
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -142,6 +142,15 @@ export class Offer {
|
||||
@Checkable.String
|
||||
H_contract: string;
|
||||
|
||||
@Checkable.Number
|
||||
offer_time: number;
|
||||
|
||||
/**
|
||||
* Serial ID when the offer is stored in the wallet DB.
|
||||
*/
|
||||
@Checkable.Optional(Checkable.Number)
|
||||
id?: number;
|
||||
|
||||
static checked: (obj: any) => Offer;
|
||||
}
|
||||
|
||||
@ -297,6 +306,15 @@ export namespace Stores {
|
||||
timestampIndex = new Index<number,HistoryRecord>(this, "timestamp", "timestamp");
|
||||
}
|
||||
|
||||
class OffersStore extends Store<Offer> {
|
||||
constructor() {
|
||||
super("offers", {
|
||||
keyPath: "id",
|
||||
autoIncrement: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TransactionsStore extends Store<Transaction> {
|
||||
constructor() {
|
||||
super("transactions", {keyPath: "contractHash"});
|
||||
@ -314,6 +332,7 @@ export namespace Stores {
|
||||
export let coins: CoinsStore = new CoinsStore();
|
||||
export let refresh: Store<RefreshSession> = new Store<RefreshSession>("refresh", {keyPath: "meltCoinPub"});
|
||||
export let history: HistoryStore = new HistoryStore();
|
||||
export let offers: OffersStore = new OffersStore();
|
||||
export let precoins: Store<PreCoin> = new Store<PreCoin>("precoins", {keyPath: "coinPub"});
|
||||
}
|
||||
|
||||
@ -585,6 +604,18 @@ export class Wallet {
|
||||
}
|
||||
|
||||
|
||||
async saveOffer(offer: Offer): Promise<number> {
|
||||
console.log(`saving offer in wallet.ts`);
|
||||
let id = await this.q().putWithResult(Stores.offers, offer);
|
||||
this.notifier.notify();
|
||||
console.log(`saved offer with id ${id}`);
|
||||
if (typeof id !== "number") {
|
||||
throw Error("db schema wrong");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add a contract to the wallet and sign coins,
|
||||
* but do not send them yet.
|
||||
@ -1525,6 +1556,12 @@ export class Wallet {
|
||||
return {history};
|
||||
}
|
||||
|
||||
|
||||
async getOffer(offerId: number): Promise<any> {
|
||||
let offer = await this.q() .get(Stores.offers, offerId);
|
||||
return offer;
|
||||
}
|
||||
|
||||
async getExchanges(): Promise<IExchangeInfo[]> {
|
||||
return this.q()
|
||||
.iter<IExchangeInfo>(Stores.exchanges)
|
||||
|
@ -168,6 +168,14 @@ function makeHandlers(db: IDBDatabase,
|
||||
}
|
||||
return wallet.putHistory(detail.historyEntry);
|
||||
},
|
||||
["save-offer"]: function (detail: any) {
|
||||
let offer = detail.offer;
|
||||
if (!offer) {
|
||||
return Promise.resolve({ error: "offer missing" });
|
||||
}
|
||||
console.log("handling safe-offer");
|
||||
return wallet.saveOffer(offer);
|
||||
},
|
||||
["reserve-creation-info"]: function (detail, sender) {
|
||||
if (!detail.baseUrl || typeof detail.baseUrl !== "string") {
|
||||
return Promise.resolve({ error: "bad url" });
|
||||
@ -183,6 +191,9 @@ function makeHandlers(db: IDBDatabase,
|
||||
// TODO: limit history length
|
||||
return wallet.getHistory();
|
||||
},
|
||||
["get-offer"]: function (detail, sender) {
|
||||
return wallet.getOffer(detail.offerId);
|
||||
},
|
||||
["get-exchanges"]: function (detail, sender) {
|
||||
return wallet.getExchanges();
|
||||
},
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
import {substituteFulfillmentUrl} from "../lib/wallet/helpers";
|
||||
import {Contract, AmountJson, IExchangeInfo} from "../lib/wallet/types";
|
||||
import {Offer} from "../lib/wallet/wallet";
|
||||
import {renderContract, prettyAmount} from "../lib/wallet/renderHtml";
|
||||
"use strict";
|
||||
import {getExchanges} from "../lib/wallet/wxApi";
|
||||
@ -43,20 +44,17 @@ interface DetailProps {
|
||||
class Details extends React.Component<DetailProps, DetailState> {
|
||||
constructor(props: DetailProps) {
|
||||
super(props);
|
||||
this.setState({
|
||||
console.log("new Details component created");
|
||||
this.state = {
|
||||
collapsed: props.collapsed,
|
||||
exchanges: null
|
||||
});
|
||||
};
|
||||
|
||||
console.log("initial state:", this.state);
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(props: DetailProps) {
|
||||
this.setState({collapsed: props.collapsed} as any);
|
||||
}
|
||||
|
||||
async update() {
|
||||
let exchanges = await getExchanges();
|
||||
this.setState({exchanges} as any);
|
||||
@ -100,10 +98,11 @@ class Details extends React.Component<DetailProps, DetailState> {
|
||||
}
|
||||
|
||||
interface ContractPromptProps {
|
||||
offer: any;
|
||||
offerId: number;
|
||||
}
|
||||
|
||||
interface ContractPromptState {
|
||||
offer: any;
|
||||
error: string|null;
|
||||
payDisabled: boolean;
|
||||
}
|
||||
@ -112,12 +111,14 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
offer: undefined,
|
||||
error: null,
|
||||
payDisabled: true,
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
this.update();
|
||||
this.checkPayment();
|
||||
}
|
||||
|
||||
@ -125,11 +126,31 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
||||
// FIXME: abort running ops
|
||||
}
|
||||
|
||||
async update() {
|
||||
let offer = await this.getOffer();
|
||||
this.setState({offer} as any);
|
||||
this.checkPayment();
|
||||
}
|
||||
|
||||
getOffer(): Promise<Offer> {
|
||||
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.props.offer
|
||||
offer: this.state.offer
|
||||
}
|
||||
};
|
||||
chrome.runtime.sendMessage(msg, (resp) => {
|
||||
@ -149,12 +170,12 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
||||
this.state.error = null;
|
||||
}
|
||||
this.setState({} as any);
|
||||
window.setTimeout(() => this.checkPayment(), 300);
|
||||
window.setTimeout(() => this.checkPayment(), 500);
|
||||
});
|
||||
}
|
||||
|
||||
doPayment() {
|
||||
let d = {offer: this.props.offer};
|
||||
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));
|
||||
@ -173,22 +194,29 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
||||
let c = d.offer.contract;
|
||||
console.log("contract", c);
|
||||
document.location.href = substituteFulfillmentUrl(c.fulfillment_url,
|
||||
this.props.offer);
|
||||
this.state.offer);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
let c = this.props.offer.contract;
|
||||
if (!this.state.offer) {
|
||||
return <span>...</span>;
|
||||
}
|
||||
let c = this.state.offer.contract;
|
||||
return (
|
||||
<div>
|
||||
{renderContract(c)}
|
||||
<div>
|
||||
{renderContract(c)}
|
||||
</div>
|
||||
<button onClick={() => this.doPayment()}
|
||||
disabled={this.state.payDisabled}
|
||||
className="accept">
|
||||
Confirm payment
|
||||
</button>
|
||||
{(this.state.error ? <p className="errorbox">{this.state.error}</p> : <p />)}
|
||||
<div>
|
||||
{(this.state.error ? <p className="errorbox">{this.state.error}</p> : <p />)}
|
||||
</div>
|
||||
<Details contract={c} collapsed={!this.state.error}/>
|
||||
</div>
|
||||
);
|
||||
@ -199,10 +227,8 @@ class ContractPrompt extends React.Component<ContractPromptProps, ContractPrompt
|
||||
export function main() {
|
||||
let url = URI(document.location.href);
|
||||
let query: any = URI.parseQuery(url.query());
|
||||
let offer = JSON.parse(query.offer);
|
||||
console.dir(offer);
|
||||
let contract = offer.contract;
|
||||
let offerId = JSON.parse(query.offerId);
|
||||
|
||||
ReactDOM.render(<ContractPrompt offer={offer}/>, document.getElementById(
|
||||
ReactDOM.render(<ContractPrompt offerId={offerId}/>, document.getElementById(
|
||||
"contract")!);
|
||||
}
|
||||
|
@ -30,4 +30,7 @@
|
||||
}
|
||||
</style>
|
||||
|
||||
<body>
|
||||
<div id="container"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -358,7 +358,7 @@ class ExchangeView extends React.Component<ExchangeProps, void> {
|
||||
}
|
||||
|
||||
interface ExchangesListState {
|
||||
exchanges: IExchangeInfo[];
|
||||
exchanges?: IExchangeInfo[];
|
||||
}
|
||||
|
||||
class ExchangesList extends React.Component<any, ExchangesListState> {
|
||||
@ -371,8 +371,8 @@ class ExchangesList extends React.Component<any, ExchangesListState> {
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
|
||||
this.update();
|
||||
this.state = {} as any;
|
||||
}
|
||||
|
||||
async update() {
|
||||
@ -382,18 +382,19 @@ class ExchangesList extends React.Component<any, ExchangesListState> {
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
if (!this.state.exchanges) {
|
||||
let exchanges = this.state.exchanges;
|
||||
if (!exchanges) {
|
||||
return <span>...</span>;
|
||||
}
|
||||
return (
|
||||
<div className="tree-item">
|
||||
Exchanges ({this.state.exchanges.length.toString()}):
|
||||
{this.state.exchanges.map(e => <ExchangeView exchange={e} />)}
|
||||
Exchanges ({exchanges.length.toString()}):
|
||||
{exchanges.map(e => <ExchangeView exchange={e} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
ReactDOM.render(<ExchangesList />, document.body);
|
||||
ReactDOM.render(<ExchangesList />, document.getElementById("container")!);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user