webpackJsonp([1],{

/***/ 155:
/***/ (function(module, exports, __webpack_require__) {

"use strict";

/*
 This file is part of TALER
 (C) 2015-2016 GNUnet e.V.

 TALER is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 TALER is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * Page shown to the user to confirm creation
 * of a reserve, usually requested by the bank.
 *
 * @author Florian Dold
 */
const helpers_1 = __webpack_require__(11);
const i18n = __webpack_require__(7);
const amounts_1 = __webpack_require__(4);
const Amounts = __webpack_require__(4);
const walletTypes_1 = __webpack_require__(156);
const components_1 = __webpack_require__(8);
const wxApi_1 = __webpack_require__(2);
const renderHtml_1 = __webpack_require__(5);
const React = __webpack_require__(1);
const ReactDOM = __webpack_require__(3);
const URI = __webpack_require__(6);
function delay(delayMs, value) {
    return new Promise((resolve, reject) => {
        setTimeout(() => resolve(value), delayMs);
    });
}
class EventTrigger {
    constructor() {
        this.reset();
    }
    reset() {
        this.triggerPromise = new Promise((resolve, reject) => {
            this.triggerResolve = resolve;
        });
    }
    trigger() {
        this.triggerResolve(false);
        this.reset();
    }
    wait(delayMs) {
        return __awaiter(this, void 0, void 0, function* () {
            return yield Promise.race([this.triggerPromise, delay(delayMs, true)]);
        });
    }
}
class ManualSelection extends components_1.ImplicitStateComponent {
    constructor(p) {
        super(p);
        this.url = this.makeState("");
        this.errorMessage = this.makeState(null);
        this.isOkay = this.makeState(false);
        this.updateEvent = new EventTrigger();
        this.url(p.initialUrl);
        this.update();
    }
    render() {
        return (React.createElement("div", { className: "pure-g pure-form pure-form-stacked" },
            React.createElement("div", { className: "pure-u-1" },
                React.createElement("label", null, "URL"),
                React.createElement("input", { className: "url", type: "text", spellCheck: false, value: this.url(), key: "exchange-url-input", onInput: (e) => this.onUrlChanged(e.target.value), onChange: (e) => this.onUrlChanged(e.target.value) })),
            React.createElement("div", { className: "pure-u-1" },
                React.createElement("button", { className: "pure-button button-success", disabled: !this.isOkay(), onClick: () => this.props.onSelect(this.url()) }, i18n.str `Select`),
                React.createElement("span", null, " "),
                this.errorMessage())));
    }
    update() {
        return __awaiter(this, void 0, void 0, function* () {
            this.errorMessage(null);
            this.isOkay(false);
            if (!this.url()) {
                return;
            }
            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 {
                const url = helpers_1.canonicalizeBaseUrl(this.url());
                yield wxApi_1.getExchangeInfo(url);
                console.log("getExchangeInfo returned");
                this.isOkay(true);
            }
            catch (e) {
                if (!(e instanceof wxApi_1.WalletApiError)) {
                    // maybe it's something more serious, don't handle here!
                    throw e;
                }
                console.log(`got error "${e.message} "with detail`, e.detail);
                this.errorMessage(i18n.str `Invalid exchange URL (${e.message})`);
            }
        });
    }
    onUrlChanged(s) {
        return __awaiter(this, void 0, void 0, function* () {
            this.url(s);
            this.errorMessage(null);
            this.isOkay(false);
            this.updateEvent.trigger();
            const waited = yield this.updateEvent.wait(200);
            if (waited) {
                // Run the actual update if nobody else preempted us.
                this.update();
            }
        });
    }
}
class ExchangeSelection extends components_1.ImplicitStateComponent {
    constructor(props) {
        super(props);
        this.statusString = this.makeState(null);
        this.reserveCreationInfo = this.makeState(null);
        this.url = this.makeState(null);
        this.selectingExchange = this.makeState(false);
        const prefilledExchangesUrls = [];
        if (props.currencyRecord) {
            const exchanges = props.currencyRecord.exchanges.map((x) => x.baseUrl);
            prefilledExchangesUrls.push(...exchanges);
        }
        if (props.suggestedExchangeUrl) {
            prefilledExchangesUrls.push(props.suggestedExchangeUrl);
        }
        if (prefilledExchangesUrls.length !== 0) {
            this.url(prefilledExchangesUrls[0]);
            this.forceReserveUpdate();
        }
        else {
            this.selectingExchange(true);
        }
    }
    renderFeeStatus() {
        const rci = this.reserveCreationInfo();
        if (rci) {
            const totalCost = Amounts.add(rci.overhead, rci.withdrawFee).amount;
            let trustMessage;
            if (rci.isTrusted) {
                trustMessage = (React.createElement(i18n.Translate, { wrap: "p" }, "The exchange is trusted by the wallet."));
            }
            else if (rci.isAudited) {
                trustMessage = (React.createElement(i18n.Translate, { wrap: "p" }, "The exchange is audited by a trusted auditor."));
            }
            else {
                trustMessage = (React.createElement(i18n.Translate, { wrap: "p" }, "Warning:  The exchange is neither directly trusted nor audited by a trusted auditor. If you withdraw from this exchange, it will be trusted in the future."));
            }
            return (React.createElement("div", null,
                React.createElement(i18n.Translate, { wrap: "p" },
                    "Using exchange provider ",
                    React.createElement("strong", null, this.url()),
                    ". The exchange provider will charge",
                    " ",
                    React.createElement("span", null, renderHtml_1.renderAmount(totalCost)),
                    " ",
                    "in fees."),
                trustMessage));
        }
        if (this.url() && !this.statusString()) {
            const shortName = new URI(this.url()).host();
            return (React.createElement(i18n.Translate, { wrap: "p" },
                "Waiting for a response from",
                React.createElement("span", null, " "),
                React.createElement("em", null, shortName)));
        }
        if (this.statusString()) {
            return (React.createElement("p", null,
                React.createElement("strong", { style: { color: "red" } }, this.statusString())));
        }
        return (React.createElement("p", null, i18n.str `Information about fees will be available when an exchange provider is selected.`));
    }
    renderUpdateStatus() {
        const rci = this.reserveCreationInfo();
        if (!rci) {
            return null;
        }
        if (!rci.versionMatch) {
            return null;
        }
        if (rci.versionMatch.compatible) {
            return null;
        }
        if (rci.versionMatch.currentCmp === -1) {
            return (React.createElement("p", { className: "errorbox" },
                React.createElement(i18n.Translate, { wrap: "span" },
                    "Your wallet (protocol version ",
                    React.createElement("span", null, rci.walletVersion),
                    ") might be outdated.",
                    React.createElement("span", null, " "),
                    "The exchange has a higher, incompatible protocol version (",
                    React.createElement("span", null, rci.exchangeVersion),
                    ").")));
        }
        if (rci.versionMatch.currentCmp === 1) {
            return (React.createElement("p", { className: "errorbox" },
                React.createElement(i18n.Translate, { wrap: "span" },
                    "The chosen exchange (protocol version ",
                    React.createElement("span", null, rci.exchangeVersion),
                    " might be outdated.",
                    React.createElement("span", null, " "),
                    "The exchange has a lower, incompatible protocol version than your wallet (protocol version ",
                    React.createElement("span", null, rci.walletVersion),
                    ").")));
        }
        throw Error("not reached");
    }
    renderConfirm() {
        return (React.createElement("div", null,
            this.renderFeeStatus(),
            React.createElement("p", null,
                React.createElement("button", { className: "pure-button button-success", disabled: this.reserveCreationInfo() === null, onClick: () => this.confirmReserve() }, i18n.str `Accept fees and withdraw`),
                " ",
                React.createElement("button", { className: "pure-button button-secondary", onClick: () => this.selectingExchange(true) }, i18n.str `Change Exchange Provider`)),
            this.renderUpdateStatus(),
            React.createElement(renderHtml_1.WithdrawDetailView, { rci: this.reserveCreationInfo() })));
    }
    select(url) {
        this.reserveCreationInfo(null);
        this.url(url);
        this.selectingExchange(false);
        this.forceReserveUpdate();
    }
    renderSelect() {
        const exchanges = (this.props.currencyRecord && this.props.currencyRecord.exchanges) || [];
        console.log(exchanges);
        return (React.createElement("div", null,
            i18n.str `Please select an exchange.  You can review the details before after your selection.`,
            this.props.suggestedExchangeUrl && (React.createElement("div", null,
                React.createElement("h2", null, "Bank Suggestion"),
                React.createElement("button", { className: "pure-button button-success", onClick: () => this.select(this.props.suggestedExchangeUrl) },
                    React.createElement(i18n.Translate, { wrap: "span" },
                        "Select ",
                        React.createElement("strong", null, this.props.suggestedExchangeUrl))))),
            exchanges.length > 0 && (React.createElement("div", null,
                React.createElement("h2", null, "Known Exchanges"),
                exchanges.map((e) => (React.createElement("button", { key: e.baseUrl, className: "pure-button button-success", onClick: () => this.select(e.baseUrl) },
                    React.createElement(i18n.Translate, null,
                        "Select ",
                        React.createElement("strong", null, e.baseUrl))))))),
            React.createElement("h2", null, "i18n.str`Manual Selection`"),
            React.createElement(ManualSelection, { initialUrl: this.url() || "", onSelect: (url) => this.select(url) })));
    }
    render() {
        return (React.createElement("div", null,
            React.createElement(i18n.Translate, { wrap: "p" },
                "You are about to withdraw",
                " ",
                React.createElement("strong", null, renderHtml_1.renderAmount(this.props.amount)),
                " ",
                "from your bank account into your wallet."),
            this.selectingExchange() ? this.renderSelect() : this.renderConfirm()));
    }
    confirmReserve() {
        this.confirmReserveImpl(this.reserveCreationInfo(), this.url(), this.props.amount, this.props.callback_url, this.props.sender_wire);
    }
    /**
     * Do an update of the reserve creation info, without any debouncing.
     */
    forceReserveUpdate() {
        return __awaiter(this, void 0, void 0, function* () {
            this.reserveCreationInfo(null);
            try {
                const url = helpers_1.canonicalizeBaseUrl(this.url());
                const r = yield wxApi_1.getReserveCreationInfo(url, this.props.amount);
                console.log("get exchange info resolved");
                this.reserveCreationInfo(r);
                console.dir(r);
            }
            catch (e) {
                console.log("get exchange info rejected", e);
                this.statusString(`Error: ${e.message}`);
                // Re-try every 5 seconds as long as there is a problem
                setTimeout(() => this.statusString() ? this.forceReserveUpdate() : undefined, 5000);
            }
        });
    }
    confirmReserveImpl(rci, exchange, amount, callback_url, sender_wire) {
        return __awaiter(this, void 0, void 0, function* () {
            const rawResp = yield wxApi_1.createReserve({
                amount,
                exchange: helpers_1.canonicalizeBaseUrl(exchange),
                senderWire: sender_wire,
            });
            if (!rawResp) {
                throw Error("empty response");
            }
            // FIXME: filter out types that bank/exchange don't have in common
            const wireDetails = rci.wireInfo;
            const filteredWireDetails = {};
            for (const wireType in wireDetails) {
                if (this.props.wt_types.findIndex((x) => x.toLowerCase() === wireType.toLowerCase()) < 0) {
                    continue;
                }
                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
                // we delete this extra data, to make the request URL shorter.
                delete obj.salt;
                delete obj.sig;
                filteredWireDetails[wireType] = obj;
            }
            if (!rawResp.error) {
                const resp = walletTypes_1.CreateReserveResponse.checked(rawResp);
                const q = {
                    amount_currency: amount.currency,
                    amount_fraction: amount.fraction,
                    amount_value: amount.value,
                    exchange: resp.exchange,
                    exchange_wire_details: JSON.stringify(filteredWireDetails),
                    reserve_pub: resp.reservePub,
                };
                const url = new URI(callback_url).addQuery(q);
                if (!url.is("absolute")) {
                    throw Error("callback url is not absolute");
                }
                console.log("going to", url.href());
                document.location.href = url.href();
            }
            else {
                this.statusString(i18n.str `Oops, something went wrong. The wallet responded with error status (${rawResp.error}).`);
            }
        });
    }
    renderStatus() {
        if (this.statusString()) {
            return React.createElement("p", null,
                React.createElement("strong", { style: { color: "red" } }, this.statusString()));
        }
        else if (!this.reserveCreationInfo()) {
            return React.createElement("p", null, i18n.str `Checking URL, please wait ...`);
        }
        return "";
    }
}
function main() {
    return __awaiter(this, void 0, void 0, function* () {
        try {
            const url = new URI(document.location.href);
            const query = URI.parseQuery(url.query());
            let amount;
            try {
                amount = amounts_1.AmountJson.checked(JSON.parse(query.amount));
            }
            catch (e) {
                throw Error(i18n.str `Can't parse amount: ${e.message}`);
            }
            const callback_url = query.callback_url;
            let wt_types;
            try {
                wt_types = JSON.parse(query.wt_types);
            }
            catch (e) {
                throw Error(i18n.str `Can't parse wire_types: ${e.message}`);
            }
            let sender_wire;
            if (query.sender_wire) {
                sender_wire = JSON.parse(query.sender_wire);
            }
            const suggestedExchangeUrl = query.suggested_exchange_url;
            const currencyRecord = yield wxApi_1.getCurrency(amount.currency);
            const args = {
                amount,
                callback_url,
                currencyRecord,
                sender_wire,
                suggestedExchangeUrl,
                wt_types,
            };
            ReactDOM.render(React.createElement(ExchangeSelection, Object.assign({}, args)), document.getElementById("exchange-selection"));
        }
        catch (e) {
            // TODO: provide more context information, maybe factor it out into a
            // TODO:generic error reporting function or component.
            document.body.innerText = i18n.str `Fatal error: "${e.message}".`;
            console.error("got error", e);
        }
    });
}
document.addEventListener("DOMContentLoaded", () => {
    main();
});


/***/ }),

/***/ 156:
/***/ (function(module, exports, __webpack_require__) {

"use strict";

/*
 This file is part of TALER
 (C) 2015-2017 GNUnet e.V. and INRIA

 TALER is free software; you can redistribute it and/or modify it under the
 terms of the GNU General Public License as published by the Free Software
 Foundation; either version 3, or (at your option) any later version.

 TALER is distributed in the hope that it will be useful, but WITHOUT ANY
 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License along with
 TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
/**
 * Types used by clients of the wallet.
 *
 * These types are defined in a separate file make tree shaking easier, since
 * some components use these types (via RPC) but do not depend on the wallet
 * code directly.
 */
/**
 * Imports.
 */
const checkable_1 = __webpack_require__(9);
const amounts_1 = __webpack_require__(4);
/**
 * Response for the create reserve request to the wallet.
 */
let CreateReserveResponse = class CreateReserveResponse {
};
__decorate([
    checkable_1.Checkable.String()
], CreateReserveResponse.prototype, "exchange", void 0);
__decorate([
    checkable_1.Checkable.String()
], CreateReserveResponse.prototype, "reservePub", void 0);
CreateReserveResponse = __decorate([
    checkable_1.Checkable.Class()
], CreateReserveResponse);
exports.CreateReserveResponse = CreateReserveResponse;
/**
 * For terseness.
 */
function mkAmount(value, fraction, currency) {
    return { value, fraction, currency };
}
exports.mkAmount = mkAmount;
/**
 * Request to mark a reserve as confirmed.
 */
let CreateReserveRequest = class CreateReserveRequest {
};
__decorate([
    checkable_1.Checkable.Value(() => amounts_1.AmountJson)
], CreateReserveRequest.prototype, "amount", void 0);
__decorate([
    checkable_1.Checkable.String()
], CreateReserveRequest.prototype, "exchange", void 0);
__decorate([
    checkable_1.Checkable.Optional(checkable_1.Checkable.Any())
], CreateReserveRequest.prototype, "senderWire", void 0);
CreateReserveRequest = __decorate([
    checkable_1.Checkable.Class()
], CreateReserveRequest);
exports.CreateReserveRequest = CreateReserveRequest;
/**
 * Request to mark a reserve as confirmed.
 */
let ConfirmReserveRequest = class ConfirmReserveRequest {
};
__decorate([
    checkable_1.Checkable.String()
], ConfirmReserveRequest.prototype, "reservePub", void 0);
ConfirmReserveRequest = __decorate([
    checkable_1.Checkable.Class()
], ConfirmReserveRequest);
exports.ConfirmReserveRequest = ConfirmReserveRequest;
/**
 * Wire coins to the user's own bank account.
 */
let ReturnCoinsRequest = class ReturnCoinsRequest {
};
__decorate([
    checkable_1.Checkable.Value(() => amounts_1.AmountJson)
], ReturnCoinsRequest.prototype, "amount", void 0);
__decorate([
    checkable_1.Checkable.String()
], ReturnCoinsRequest.prototype, "exchange", void 0);
__decorate([
    checkable_1.Checkable.Any()
], ReturnCoinsRequest.prototype, "senderWire", void 0);
ReturnCoinsRequest = __decorate([
    checkable_1.Checkable.Class()
], ReturnCoinsRequest);
exports.ReturnCoinsRequest = ReturnCoinsRequest;


/***/ })

},[155]);
//# sourceMappingURL=confirm-create-reserve-bundle.js.map