new balances API, remove defunct 'return funds to own account' implementation
This commit is contained in:
parent
43655adff0
commit
732e764b37
@ -197,14 +197,7 @@ walletCli
|
||||
.action(async (args) => {
|
||||
await withWallet(args, async (wallet) => {
|
||||
const balance = await wallet.getBalances();
|
||||
if (args.balance.json) {
|
||||
console.log(JSON.stringify(balance, undefined, 2));
|
||||
} else {
|
||||
const currencies = Object.keys(balance.byCurrency).sort();
|
||||
for (const c of currencies) {
|
||||
console.log(Amounts.stringify(balance.byCurrency[c].available));
|
||||
}
|
||||
}
|
||||
console.log(JSON.stringify(balance, undefined, 2));
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import { WalletBalance, WalletBalanceEntry } from "../types/walletTypes";
|
||||
import { BalancesResponse } from "../types/walletTypes";
|
||||
import { TransactionHandle } from "../util/query";
|
||||
import { InternalWalletState } from "./state";
|
||||
import { Stores, CoinStatus } from "../types/dbTypes";
|
||||
@ -27,63 +27,49 @@ import { Logger } from "../util/logging";
|
||||
|
||||
const logger = new Logger("withdraw.ts");
|
||||
|
||||
interface WalletBalance {
|
||||
available: AmountJson;
|
||||
pendingIncoming: AmountJson;
|
||||
pendingOutgoing: AmountJson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get balance information.
|
||||
*/
|
||||
export async function getBalancesInsideTransaction(
|
||||
ws: InternalWalletState,
|
||||
tx: TransactionHandle,
|
||||
): Promise<WalletBalance> {
|
||||
): Promise<BalancesResponse> {
|
||||
|
||||
const balanceStore: Record<string, WalletBalance> = {};
|
||||
|
||||
/**
|
||||
* Add amount to a balance field, both for
|
||||
* the slicing by exchange and currency.
|
||||
*/
|
||||
function addTo(
|
||||
balance: WalletBalance,
|
||||
field: keyof WalletBalanceEntry,
|
||||
amount: AmountJson,
|
||||
exchange: string,
|
||||
): void {
|
||||
const z = Amounts.getZero(amount.currency);
|
||||
const balanceIdentity = {
|
||||
available: z,
|
||||
paybackAmount: z,
|
||||
pendingIncoming: z,
|
||||
pendingPayment: z,
|
||||
pendingIncomingDirty: z,
|
||||
pendingIncomingRefresh: z,
|
||||
pendingIncomingWithdraw: z,
|
||||
};
|
||||
let entryCurr = balance.byCurrency[amount.currency];
|
||||
if (!entryCurr) {
|
||||
balance.byCurrency[amount.currency] = entryCurr = {
|
||||
...balanceIdentity,
|
||||
const initBalance = (currency: string): WalletBalance => {
|
||||
const b = balanceStore[currency];
|
||||
if (!b) {
|
||||
balanceStore[currency] = {
|
||||
available: Amounts.getZero(currency),
|
||||
pendingIncoming: Amounts.getZero(currency),
|
||||
pendingOutgoing: Amounts.getZero(currency),
|
||||
};
|
||||
}
|
||||
let entryEx = balance.byExchange[exchange];
|
||||
if (!entryEx) {
|
||||
balance.byExchange[exchange] = entryEx = { ...balanceIdentity };
|
||||
}
|
||||
entryCurr[field] = Amounts.add(entryCurr[field], amount).amount;
|
||||
entryEx[field] = Amounts.add(entryEx[field], amount).amount;
|
||||
return balanceStore[currency];
|
||||
}
|
||||
|
||||
const balanceStore = {
|
||||
byCurrency: {},
|
||||
byExchange: {},
|
||||
};
|
||||
|
||||
// Initialize balance to zero, even if we didn't start withdrawing yet.
|
||||
await tx.iter(Stores.reserves).forEach((r) => {
|
||||
const z = Amounts.getZero(r.currency);
|
||||
addTo(balanceStore, "available", z, r.exchangeBaseUrl);
|
||||
initBalance(r.currency);
|
||||
});
|
||||
|
||||
await tx.iter(Stores.coins).forEach((c) => {
|
||||
if (c.suspended) {
|
||||
return;
|
||||
}
|
||||
// Only count fresh coins, as dormant coins will
|
||||
// already be in a refresh session.
|
||||
if (c.status === CoinStatus.Fresh) {
|
||||
addTo(balanceStore, "available", c.currentAmount, c.exchangeBaseUrl);
|
||||
const b = initBalance(c.currentAmount.currency);
|
||||
b.available = Amounts.add(b.available, c.currentAmount).amount;
|
||||
}
|
||||
});
|
||||
|
||||
@ -96,51 +82,38 @@ export async function getBalancesInsideTransaction(
|
||||
for (let i = 0; i < r.oldCoinPubs.length; i++) {
|
||||
const session = r.refreshSessionPerCoin[i];
|
||||
if (session) {
|
||||
addTo(
|
||||
balanceStore,
|
||||
"pendingIncoming",
|
||||
session.amountRefreshOutput,
|
||||
session.exchangeBaseUrl,
|
||||
);
|
||||
addTo(
|
||||
balanceStore,
|
||||
"pendingIncomingRefresh",
|
||||
session.amountRefreshOutput,
|
||||
session.exchangeBaseUrl,
|
||||
);
|
||||
const b = initBalance(session.amountRefreshOutput.currency);
|
||||
// We are always assuming the refresh will succeed, thus we
|
||||
// report the output as available balance.
|
||||
b.available = Amounts.add(session.amountRefreshOutput).amount;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// FIXME: re-implement
|
||||
// await tx.iter(Stores.withdrawalGroups).forEach((wds) => {
|
||||
// let w = wds.totalCoinValue;
|
||||
// for (let i = 0; i < wds.planchets.length; i++) {
|
||||
// if (wds.withdrawn[i]) {
|
||||
// const p = wds.planchets[i];
|
||||
// if (p) {
|
||||
// w = Amounts.sub(w, p.coinValue).amount;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// addTo(balanceStore, "pendingIncoming", w, wds.exchangeBaseUrl);
|
||||
// });
|
||||
|
||||
await tx.iter(Stores.purchases).forEach((t) => {
|
||||
if (t.timestampFirstSuccessfulPay) {
|
||||
await tx.iter(Stores.withdrawalGroups).forEach((wds) => {
|
||||
if (wds.timestampFinish) {
|
||||
return;
|
||||
}
|
||||
for (const c of t.coinDepositPermissions) {
|
||||
addTo(
|
||||
balanceStore,
|
||||
"pendingPayment",
|
||||
Amounts.parseOrThrow(c.contribution),
|
||||
c.exchange_url,
|
||||
);
|
||||
}
|
||||
const b = initBalance(wds.denomsSel.totalWithdrawCost.currency);
|
||||
b.pendingIncoming = Amounts.add(b.pendingIncoming, wds.denomsSel.totalCoinValue).amount;
|
||||
});
|
||||
|
||||
return balanceStore;
|
||||
const balancesResponse: BalancesResponse = {
|
||||
balances: [],
|
||||
};
|
||||
|
||||
Object.keys(balanceStore).sort().forEach((c) => {
|
||||
const v = balanceStore[c];
|
||||
balancesResponse.balances.push({
|
||||
available: Amounts.stringify(v.available),
|
||||
pendingIncoming: Amounts.stringify(v.pendingIncoming),
|
||||
pendingOutgoing: Amounts.stringify(v.pendingOutgoing),
|
||||
hasPendingTransactions: false,
|
||||
requiresUserInput: false,
|
||||
});
|
||||
})
|
||||
|
||||
return balancesResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,7 +121,7 @@ export async function getBalancesInsideTransaction(
|
||||
*/
|
||||
export async function getBalances(
|
||||
ws: InternalWalletState,
|
||||
): Promise<WalletBalance> {
|
||||
): Promise<BalancesResponse> {
|
||||
logger.trace("starting to compute balance");
|
||||
|
||||
const wbal = await ws.db.runWithReadTransaction(
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { HttpRequestLibrary } from "../util/http";
|
||||
import { NextUrlResult, WalletBalance } from "../types/walletTypes";
|
||||
import { NextUrlResult, BalancesResponse } from "../types/walletTypes";
|
||||
import { CryptoApi, CryptoWorkerFactory } from "../crypto/workers/cryptoApi";
|
||||
import { AsyncOpMemoMap, AsyncOpMemoSingle } from "../util/asyncMemo";
|
||||
import { Logger } from "../util/logging";
|
||||
@ -34,7 +34,7 @@ export class InternalWalletState {
|
||||
memoGetPending: AsyncOpMemoSingle<
|
||||
PendingOperationsResponse
|
||||
> = new AsyncOpMemoSingle();
|
||||
memoGetBalance: AsyncOpMemoSingle<WalletBalance> = new AsyncOpMemoSingle();
|
||||
memoGetBalance: AsyncOpMemoSingle<BalancesResponse> = new AsyncOpMemoSingle();
|
||||
memoProcessRefresh: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
||||
memoProcessRecoup: AsyncOpMemoMap<void> = new AsyncOpMemoMap();
|
||||
cryptoApi: CryptoApi;
|
||||
|
@ -21,7 +21,7 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
import { OperationErrorDetails, WalletBalance } from "./walletTypes";
|
||||
import { OperationErrorDetails, BalancesResponse } from "./walletTypes";
|
||||
import { WithdrawalSource, RetryInfo, ReserveRecordStatus } from "./dbTypes";
|
||||
import { Timestamp, Duration } from "../util/time";
|
||||
|
||||
@ -243,7 +243,7 @@ export interface PendingOperationsResponse {
|
||||
/**
|
||||
* Current wallet balance, including pending balances.
|
||||
*/
|
||||
walletBalance: WalletBalance;
|
||||
walletBalance: BalancesResponse;
|
||||
|
||||
/**
|
||||
* When is the next pending operation due to be re-tried?
|
||||
|
@ -146,48 +146,26 @@ export interface ExchangeWithdrawDetails {
|
||||
walletVersion: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mapping from currency/exchange to detailed balance
|
||||
* information.
|
||||
*/
|
||||
export interface WalletBalance {
|
||||
/**
|
||||
* Mapping from currency name to detailed balance info.
|
||||
*/
|
||||
byExchange: { [exchangeBaseUrl: string]: WalletBalanceEntry };
|
||||
|
||||
/**
|
||||
* Mapping from currency name to detailed balance info.
|
||||
*/
|
||||
byCurrency: { [currency: string]: WalletBalanceEntry };
|
||||
export interface Balance {
|
||||
available: AmountString;
|
||||
pendingIncoming: AmountString;
|
||||
pendingOutgoing: AmountString;
|
||||
|
||||
// Does the balance for this currency have a pending
|
||||
// transaction?
|
||||
hasPendingTransactions: boolean;
|
||||
|
||||
// Is there a pending transaction that would affect the balance
|
||||
// and requires user input?
|
||||
requiresUserInput: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detailed wallet balance for a particular currency.
|
||||
*/
|
||||
export interface WalletBalanceEntry {
|
||||
/**
|
||||
* Directly available amount.
|
||||
*/
|
||||
available: AmountJson;
|
||||
/**
|
||||
* Amount that we're waiting for (refresh, withdrawal).
|
||||
*/
|
||||
pendingIncoming: AmountJson;
|
||||
/**
|
||||
* Amount that's marked for a pending payment.
|
||||
*/
|
||||
pendingPayment: AmountJson;
|
||||
/**
|
||||
* Amount that was paid back and we could withdraw again.
|
||||
*/
|
||||
paybackAmount: AmountJson;
|
||||
|
||||
pendingIncomingWithdraw: AmountJson;
|
||||
pendingIncomingRefresh: AmountJson;
|
||||
pendingIncomingDirty: AmountJson;
|
||||
export interface BalancesResponse {
|
||||
balances: Balance[];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For terseness.
|
||||
*/
|
||||
|
@ -60,7 +60,6 @@ import {
|
||||
ReturnCoinsRequest,
|
||||
SenderWireInfos,
|
||||
TipStatus,
|
||||
WalletBalance,
|
||||
PreparePayResult,
|
||||
AcceptWithdrawalResponse,
|
||||
PurchaseDetails,
|
||||
@ -70,6 +69,7 @@ import {
|
||||
ManualWithdrawalDetails,
|
||||
GetExchangeTosResult,
|
||||
AcceptManualWithdrawalResult,
|
||||
BalancesResponse,
|
||||
} from "./types/walletTypes";
|
||||
import { Logger } from "./util/logging";
|
||||
|
||||
@ -515,7 +515,7 @@ export class Wallet {
|
||||
/**
|
||||
* Get detailed balance information, sliced by exchange and by currency.
|
||||
*/
|
||||
async getBalances(): Promise<WalletBalance> {
|
||||
async getBalances(): Promise<BalancesResponse> {
|
||||
return this.ws.memoGetBalance.memo(() => getBalances(this.ws));
|
||||
}
|
||||
|
||||
|
@ -29,8 +29,6 @@ import * as i18n from "../i18n";
|
||||
import { AmountJson } from "../../util/amounts";
|
||||
import * as Amounts from "../../util/amounts";
|
||||
|
||||
import { WalletBalance, WalletBalanceEntry } from "../../types/walletTypes";
|
||||
|
||||
import { abbrev, renderAmount, PageLink } from "../renderHtml";
|
||||
import * as wxApi from "../wxApi";
|
||||
|
||||
@ -40,6 +38,7 @@ import moment from "moment";
|
||||
import { Timestamp } from "../../util/time";
|
||||
import { classifyTalerUri, TalerUriType } from "../../util/taleruri";
|
||||
import { PermissionsCheckbox } from "./welcome";
|
||||
import { BalancesResponse, Balance } from "../../types/walletTypes";
|
||||
|
||||
// FIXME: move to newer react functions
|
||||
/* eslint-disable react/no-deprecated */
|
||||
@ -172,7 +171,7 @@ function EmptyBalanceView(): JSX.Element {
|
||||
}
|
||||
|
||||
class WalletBalanceView extends React.Component<any, any> {
|
||||
private balance: WalletBalance;
|
||||
private balance: BalancesResponse;
|
||||
private gotError = false;
|
||||
private canceler: (() => void) | undefined = undefined;
|
||||
private unmount = false;
|
||||
@ -196,7 +195,7 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
return;
|
||||
}
|
||||
this.updateBalanceRunning = true;
|
||||
let balance: WalletBalance;
|
||||
let balance: BalancesResponse;
|
||||
try {
|
||||
balance = await wxApi.getBalance();
|
||||
} catch (e) {
|
||||
@ -219,10 +218,14 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
this.setState({});
|
||||
}
|
||||
|
||||
formatPending(entry: WalletBalanceEntry): JSX.Element {
|
||||
formatPending(entry: Balance): JSX.Element {
|
||||
let incoming: JSX.Element | undefined;
|
||||
let payment: JSX.Element | undefined;
|
||||
|
||||
const available = Amounts.parseOrThrow(entry.available);
|
||||
const pendingIncoming = Amounts.parseOrThrow(entry.pendingIncoming);
|
||||
const pendingOutgoing = Amounts.parseOrThrow(entry.pendingOutgoing);
|
||||
|
||||
console.log(
|
||||
"available: ",
|
||||
entry.pendingIncoming ? renderAmount(entry.available) : null,
|
||||
@ -232,7 +235,7 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
entry.pendingIncoming ? renderAmount(entry.pendingIncoming) : null,
|
||||
);
|
||||
|
||||
if (Amounts.isNonZero(entry.pendingIncoming)) {
|
||||
if (Amounts.isNonZero(pendingIncoming)) {
|
||||
incoming = (
|
||||
<i18n.Translate wrap="span">
|
||||
<span style={{ color: "darkgreen" }}>
|
||||
@ -244,18 +247,6 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
);
|
||||
}
|
||||
|
||||
if (Amounts.isNonZero(entry.pendingPayment)) {
|
||||
payment = (
|
||||
<i18n.Translate wrap="span">
|
||||
<span style={{ color: "red" }}>
|
||||
{"-"}
|
||||
{renderAmount(entry.pendingPayment)}
|
||||
</span>{" "}
|
||||
being spent
|
||||
</i18n.Translate>
|
||||
);
|
||||
}
|
||||
|
||||
const l = [incoming, payment].filter((x) => x !== undefined);
|
||||
if (l.length === 0) {
|
||||
return <span />;
|
||||
@ -288,11 +279,11 @@ class WalletBalanceView extends React.Component<any, any> {
|
||||
return <span></span>;
|
||||
}
|
||||
console.log(wallet);
|
||||
const listing = Object.keys(wallet.byCurrency).map((key) => {
|
||||
const entry: WalletBalanceEntry = wallet.byCurrency[key];
|
||||
const listing = wallet.balances.map((entry) => {
|
||||
const av = Amounts.parseOrThrow(entry.available);
|
||||
return (
|
||||
<p key={key}>
|
||||
{bigAmount(entry.available)} {this.formatPending(entry)}
|
||||
<p key={av.currency}>
|
||||
{bigAmount(av)} {this.formatPending(entry)}
|
||||
</p>
|
||||
);
|
||||
});
|
||||
@ -314,7 +305,6 @@ function formatAndCapitalize(text: string): string {
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
const HistoryComponent = (props: any): JSX.Element => {
|
||||
return <span>TBD</span>;
|
||||
};
|
||||
@ -330,7 +320,6 @@ class WalletSettings extends React.Component<any, any> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function reload(): void {
|
||||
try {
|
||||
chrome.runtime.reload();
|
||||
|
@ -23,293 +23,8 @@
|
||||
/**
|
||||
* Imports.
|
||||
*/
|
||||
|
||||
import { AmountJson } from "../../util/amounts";
|
||||
import { Amounts } from "../../util/amounts";
|
||||
|
||||
import { SenderWireInfos, WalletBalance } from "../../types/walletTypes";
|
||||
|
||||
import * as i18n from "../i18n";
|
||||
|
||||
import * as wire from "../../util/wire";
|
||||
|
||||
import { getBalance, getSenderWireInfos, returnCoins } from "../wxApi";
|
||||
|
||||
import { renderAmount } from "../renderHtml";
|
||||
|
||||
import * as React from "react";
|
||||
|
||||
interface ReturnSelectionItemProps extends ReturnSelectionListProps {
|
||||
exchangeUrl: string;
|
||||
senderWireInfos: SenderWireInfos;
|
||||
}
|
||||
|
||||
interface ReturnSelectionItemState {
|
||||
selectedValue: string;
|
||||
supportedWires: string[];
|
||||
selectedWire: string;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
class ReturnSelectionItem extends React.Component<
|
||||
ReturnSelectionItemProps,
|
||||
ReturnSelectionItemState
|
||||
> {
|
||||
constructor(props: ReturnSelectionItemProps) {
|
||||
super(props);
|
||||
const exchange = this.props.exchangeUrl;
|
||||
const wireTypes = this.props.senderWireInfos.exchangeWireTypes;
|
||||
const supportedWires = this.props.senderWireInfos.senderWires.filter(
|
||||
(x) => {
|
||||
return (
|
||||
wireTypes[exchange] &&
|
||||
wireTypes[exchange].indexOf((x as any).type) >= 0
|
||||
);
|
||||
},
|
||||
);
|
||||
this.state = {
|
||||
currency: props.balance.byExchange[props.exchangeUrl].available.currency,
|
||||
selectedValue: Amounts.stringify(
|
||||
props.balance.byExchange[props.exchangeUrl].available,
|
||||
),
|
||||
selectedWire: "",
|
||||
supportedWires,
|
||||
};
|
||||
}
|
||||
render(): JSX.Element {
|
||||
const exchange = this.props.exchangeUrl;
|
||||
const byExchange = this.props.balance.byExchange;
|
||||
const wireTypes = this.props.senderWireInfos.exchangeWireTypes;
|
||||
return (
|
||||
<div key={exchange}>
|
||||
<h2>Exchange {exchange}</h2>
|
||||
<p>Available amount: {renderAmount(byExchange[exchange].available)}</p>
|
||||
<p>
|
||||
Supported wire methods:{" "}
|
||||
{wireTypes[exchange].length ? wireTypes[exchange].join(", ") : "none"}
|
||||
</p>
|
||||
<p>
|
||||
Wire {""}
|
||||
<input
|
||||
type="text"
|
||||
size={this.state.selectedValue.length || 1}
|
||||
value={this.state.selectedValue}
|
||||
onChange={(evt) =>
|
||||
this.setState({ selectedValue: evt.target.value })
|
||||
}
|
||||
style={{ textAlign: "center" }}
|
||||
/>{" "}
|
||||
{this.props.balance.byExchange[exchange].available.currency} {""}
|
||||
to account {""}
|
||||
<select
|
||||
value={this.state.selectedWire}
|
||||
onChange={(evt) =>
|
||||
this.setState({ selectedWire: evt.target.value })
|
||||
}
|
||||
>
|
||||
<option style={{ display: "none" }}>Select account</option>
|
||||
{this.state.supportedWires.map((w, n) => (
|
||||
<option value={n.toString()} key={JSON.stringify(w)}>
|
||||
{n + 1}: {wire.summarizeWire(w)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
.
|
||||
</p>
|
||||
{this.state.selectedWire ? (
|
||||
<button
|
||||
className="pure-button button-success"
|
||||
onClick={() => this.select()}
|
||||
>
|
||||
{i18n.str`Wire to bank account`}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
select(): void {
|
||||
let val: number;
|
||||
let selectedWire: number;
|
||||
try {
|
||||
val = Number.parseFloat(this.state.selectedValue);
|
||||
selectedWire = Number.parseInt(this.state.selectedWire);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
this.props.selectDetail({
|
||||
amount: Amounts.fromFloat(val, this.state.currency),
|
||||
exchange: this.props.exchangeUrl,
|
||||
senderWire: this.state.supportedWires[selectedWire],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
interface ReturnSelectionListProps {
|
||||
balance: WalletBalance;
|
||||
senderWireInfos: SenderWireInfos;
|
||||
selectDetail(d: SelectedDetail): void;
|
||||
}
|
||||
|
||||
class ReturnSelectionList extends React.Component<
|
||||
ReturnSelectionListProps,
|
||||
{}
|
||||
> {
|
||||
render(): JSX.Element {
|
||||
const byExchange = this.props.balance.byExchange;
|
||||
const exchanges = Object.keys(byExchange);
|
||||
if (!exchanges.length) {
|
||||
return (
|
||||
<p className="errorbox">Currently no funds available to transfer.</p>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
{exchanges.map((e) => (
|
||||
<ReturnSelectionItem key={e} exchangeUrl={e} {...this.props} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface SelectedDetail {
|
||||
amount: AmountJson;
|
||||
senderWire: any;
|
||||
exchange: string;
|
||||
}
|
||||
|
||||
interface ReturnConfirmationProps {
|
||||
detail: SelectedDetail;
|
||||
cancel(): void;
|
||||
confirm(): void;
|
||||
}
|
||||
|
||||
class ReturnConfirmation extends React.Component<ReturnConfirmationProps, {}> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div>
|
||||
<p>
|
||||
Please confirm if you want to transmit{" "}
|
||||
<strong>{renderAmount(this.props.detail.amount)}</strong> at {""}
|
||||
{this.props.detail.exchange} to account {""}
|
||||
<strong style={{ whiteSpace: "nowrap" }}>
|
||||
{wire.summarizeWire(this.props.detail.senderWire)}
|
||||
</strong>
|
||||
.
|
||||
</p>
|
||||
<button
|
||||
className="pure-button button-success"
|
||||
onClick={() => this.props.confirm()}
|
||||
>
|
||||
{i18n.str`Confirm`}
|
||||
</button>
|
||||
<button className="pure-button" onClick={() => this.props.cancel()}>
|
||||
{i18n.str`Cancel`}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
interface ReturnCoinsState {
|
||||
balance: WalletBalance | undefined;
|
||||
senderWireInfos: SenderWireInfos | undefined;
|
||||
selectedReturn: SelectedDetail | undefined;
|
||||
/**
|
||||
* Last confirmed detail, so we can show a nice box.
|
||||
*/
|
||||
lastConfirmedDetail: SelectedDetail | undefined;
|
||||
}
|
||||
|
||||
class ReturnCoins extends React.Component<{}, ReturnCoinsState> {
|
||||
constructor(props: {}) {
|
||||
super(props);
|
||||
const port = chrome.runtime.connect();
|
||||
port.onMessage.addListener((msg: any) => {
|
||||
if (msg.notify) {
|
||||
console.log("got notified");
|
||||
this.update();
|
||||
}
|
||||
});
|
||||
this.update();
|
||||
this.state = {} as any;
|
||||
}
|
||||
|
||||
async update(): Promise<void> {
|
||||
const balance = await getBalance();
|
||||
const senderWireInfos = await getSenderWireInfos();
|
||||
console.log("got swi", senderWireInfos);
|
||||
console.log("got bal", balance);
|
||||
this.setState({ balance, senderWireInfos });
|
||||
}
|
||||
|
||||
selectDetail(d: SelectedDetail): void {
|
||||
this.setState({ selectedReturn: d });
|
||||
}
|
||||
|
||||
async confirm(): Promise<void> {
|
||||
const selectedReturn = this.state.selectedReturn;
|
||||
if (!selectedReturn) {
|
||||
return;
|
||||
}
|
||||
await returnCoins(selectedReturn);
|
||||
await this.update();
|
||||
this.setState({
|
||||
selectedReturn: undefined,
|
||||
lastConfirmedDetail: selectedReturn,
|
||||
});
|
||||
}
|
||||
|
||||
async cancel(): Promise<void> {
|
||||
this.setState({
|
||||
selectedReturn: undefined,
|
||||
lastConfirmedDetail: undefined,
|
||||
});
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const balance = this.state.balance;
|
||||
const senderWireInfos = this.state.senderWireInfos;
|
||||
if (!balance || !senderWireInfos) {
|
||||
return <span>...</span>;
|
||||
}
|
||||
if (this.state.selectedReturn) {
|
||||
return (
|
||||
<div id="main">
|
||||
<ReturnConfirmation
|
||||
detail={this.state.selectedReturn}
|
||||
cancel={() => this.cancel()}
|
||||
confirm={() => this.confirm()}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div id="main">
|
||||
<h1>Wire electronic cash back to own bank account</h1>
|
||||
<p>
|
||||
You can send coins back into your own bank account. Note that
|
||||
you're acting as a merchant when doing this, and thus the same
|
||||
fees apply.
|
||||
</p>
|
||||
{this.state.lastConfirmedDetail ? (
|
||||
<p className="okaybox">
|
||||
Transfer of {renderAmount(this.state.lastConfirmedDetail.amount)}{" "}
|
||||
successfully initiated.
|
||||
</p>
|
||||
) : null}
|
||||
<ReturnSelectionList
|
||||
selectDetail={(d) => this.selectDetail(d)}
|
||||
balance={balance}
|
||||
senderWireInfos={senderWireInfos}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function createReturnCoinsPage(): JSX.Element {
|
||||
return <ReturnCoins />;
|
||||
return <span>Not implemented yet.</span>;
|
||||
}
|
||||
|
@ -34,12 +34,12 @@ import {
|
||||
ConfirmPayResult,
|
||||
SenderWireInfos,
|
||||
TipStatus,
|
||||
WalletBalance,
|
||||
PurchaseDetails,
|
||||
WalletDiagnostics,
|
||||
PreparePayResult,
|
||||
AcceptWithdrawalResponse,
|
||||
ExtendedPermissionsResponse,
|
||||
BalancesResponse,
|
||||
} from "../types/walletTypes";
|
||||
|
||||
/**
|
||||
@ -185,7 +185,7 @@ export function resetDb(): Promise<void> {
|
||||
/**
|
||||
* Get balances for all currencies/exchanges.
|
||||
*/
|
||||
export function getBalance(): Promise<WalletBalance> {
|
||||
export function getBalance(): Promise<BalancesResponse> {
|
||||
return callBackend("balances", {});
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user