manual withdrawal process
This commit is contained in:
parent
9a0285ee4b
commit
8cde98947b
@ -33,6 +33,7 @@ import { PopupNavigation } from './components/styled'
|
|||||||
export enum Pages {
|
export enum Pages {
|
||||||
welcome = '/welcome',
|
welcome = '/welcome',
|
||||||
balance = '/balance',
|
balance = '/balance',
|
||||||
|
manual_withdraw = '/manual-withdraw',
|
||||||
settings = '/settings',
|
settings = '/settings',
|
||||||
dev = '/dev',
|
dev = '/dev',
|
||||||
backup = '/backup',
|
backup = '/backup',
|
||||||
|
@ -486,6 +486,33 @@ export const Input = styled.div<{ invalid?: boolean }>`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const InputWithLabel = styled.div<{ invalid?: boolean }>`
|
||||||
|
& label {
|
||||||
|
display: block;
|
||||||
|
padding: 5px;
|
||||||
|
color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
|
||||||
|
}
|
||||||
|
& > div {
|
||||||
|
position: relative;
|
||||||
|
display: flex;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
position: absolute;
|
||||||
|
background-color: lightgray;
|
||||||
|
padding: 5px;
|
||||||
|
margin: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 5px;
|
||||||
|
border-color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
export const ErrorBox = styled.div`
|
export const ErrorBox = styled.div`
|
||||||
border: 2px solid #f5c6cb;
|
border: 2px solid #f5c6cb;
|
||||||
border-radius: 0.25em;
|
border-radius: 0.25em;
|
||||||
|
@ -141,7 +141,7 @@ export function View({ details, amount, onWithdraw, terms, reviewing, onReview,
|
|||||||
}
|
}
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
{terms.status === 'new' && !accepted &&
|
{terms.status === 'new' && !accepted && !reviewing &&
|
||||||
<ButtonSuccess
|
<ButtonSuccess
|
||||||
upperCased
|
upperCased
|
||||||
disabled={!details.exchangeInfo.baseUrl}
|
disabled={!details.exchangeInfo.baseUrl}
|
||||||
|
@ -20,20 +20,21 @@ import {
|
|||||||
i18n
|
i18n
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { JSX, h } from "preact";
|
import { JSX, h } from "preact";
|
||||||
import { PopupBox, Centered } from "../components/styled/index";
|
import { PopupBox, Centered, ButtonPrimary } from "../components/styled/index";
|
||||||
import { BalancesHook, useBalances } from "../hooks/useBalances";
|
import { BalancesHook, useBalances } from "../hooks/useBalances";
|
||||||
import { PageLink, renderAmount } from "../renderHtml";
|
import { PageLink, renderAmount } from "../renderHtml";
|
||||||
|
|
||||||
|
|
||||||
export function BalancePage() {
|
export function BalancePage({ goToWalletManualWithdraw }: { goToWalletManualWithdraw: () => void }) {
|
||||||
const balance = useBalances()
|
const balance = useBalances()
|
||||||
return <BalanceView balance={balance} Linker={PageLink} />
|
return <BalanceView balance={balance} Linker={PageLink} goToWalletManualWithdraw={goToWalletManualWithdraw} />
|
||||||
}
|
}
|
||||||
export interface BalanceViewProps {
|
export interface BalanceViewProps {
|
||||||
balance: BalancesHook,
|
balance: BalancesHook;
|
||||||
Linker: typeof PageLink,
|
Linker: typeof PageLink;
|
||||||
|
goToWalletManualWithdraw: () => void;
|
||||||
}
|
}
|
||||||
export function BalanceView({ balance, Linker }: BalanceViewProps) {
|
export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) {
|
||||||
if (!balance) {
|
if (!balance) {
|
||||||
return <span />
|
return <span />
|
||||||
}
|
}
|
||||||
@ -57,7 +58,9 @@ export function BalanceView({ balance, Linker }: BalanceViewProps) {
|
|||||||
</i18n.Translate></p>
|
</i18n.Translate></p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <ShowBalances wallet={balance.response} />
|
return <ShowBalances wallet={balance.response}
|
||||||
|
onWithdraw={goToWalletManualWithdraw}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPending(entry: Balance): JSX.Element {
|
function formatPending(entry: Balance): JSX.Element {
|
||||||
@ -96,7 +99,7 @@ function formatPending(entry: Balance): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ShowBalances({ wallet }: { wallet: BalancesResponse }) {
|
function ShowBalances({ wallet, onWithdraw }: { wallet: BalancesResponse, onWithdraw: () => void }) {
|
||||||
return <PopupBox>
|
return <PopupBox>
|
||||||
<section>
|
<section>
|
||||||
<Centered>{wallet.balances.map((entry) => {
|
<Centered>{wallet.balances.map((entry) => {
|
||||||
@ -113,5 +116,9 @@ function ShowBalances({ wallet }: { wallet: BalancesResponse }) {
|
|||||||
);
|
);
|
||||||
})}</Centered>
|
})}</Centered>
|
||||||
</section>
|
</section>
|
||||||
|
<footer>
|
||||||
|
<div />
|
||||||
|
<ButtonPrimary onClick={onWithdraw} >Withdraw</ButtonPrimary>
|
||||||
|
</footer>
|
||||||
</PopupBox>
|
</PopupBox>
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,8 @@
|
|||||||
|
|
||||||
import { setupI18n } from "@gnu-taler/taler-util";
|
import { setupI18n } from "@gnu-taler/taler-util";
|
||||||
import { createHashHistory } from "history";
|
import { createHashHistory } from "history";
|
||||||
import { render, h } from "preact";
|
import { render, h, VNode } from "preact";
|
||||||
import Router, { route, Route } from "preact-router";
|
import Router, { route, Route, getCurrentUrl } from "preact-router";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { DevContextProvider } from "./context/devContext";
|
import { DevContextProvider } from "./context/devContext";
|
||||||
import { useTalerActionURL } from "./hooks/useTalerActionURL";
|
import { useTalerActionURL } from "./hooks/useTalerActionURL";
|
||||||
@ -96,9 +96,16 @@ function Application() {
|
|||||||
<WalletNavBar />
|
<WalletNavBar />
|
||||||
<div style={{ width: 400, height: 290 }}>
|
<div style={{ width: 400, height: 290 }}>
|
||||||
<Router history={createHashHistory()}>
|
<Router history={createHashHistory()}>
|
||||||
<Route path={Pages.balance} component={BalancePage} />
|
<Route path={Pages.balance} component={BalancePage}
|
||||||
|
goToWalletManualWithdraw={() => goToWalletPage(Pages.manual_withdraw)}
|
||||||
|
/>
|
||||||
<Route path={Pages.settings} component={SettingsPage} />
|
<Route path={Pages.settings} component={SettingsPage} />
|
||||||
<Route path={Pages.dev} component={DeveloperPage} />
|
<Route path={Pages.dev} component={DeveloperPage} />
|
||||||
|
|
||||||
|
<Route path={Pages.transaction}
|
||||||
|
component={({ tid }: { tid: string }) => goToWalletPage(Pages.transaction.replace(':tid', tid))}
|
||||||
|
/>
|
||||||
|
|
||||||
<Route path={Pages.history} component={HistoryPage} />
|
<Route path={Pages.history} component={HistoryPage} />
|
||||||
<Route path={Pages.backup} component={BackupPage}
|
<Route path={Pages.backup} component={BackupPage}
|
||||||
onAddProvider={() => {
|
onAddProvider={() => {
|
||||||
@ -123,6 +130,13 @@ function Application() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function goToWalletPage(page: Pages | string): null {
|
||||||
|
chrome.tabs.create({
|
||||||
|
active: true,
|
||||||
|
url: chrome.extension.getURL(`/static/wallet.html#${page}`),
|
||||||
|
})
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
function Redirect({ to }: { to: string }): null {
|
function Redirect({ to }: { to: string }): null {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
@ -57,7 +57,7 @@ export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps):
|
|||||||
title={provider.name}
|
title={provider.name}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{!providers.length && <Centered style={{marginTop: 100}}>
|
{!providers.length && <Centered style={{ marginTop: 100 }}>
|
||||||
<BoldLight>No backup providers configured</BoldLight>
|
<BoldLight>No backup providers configured</BoldLight>
|
||||||
<ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
|
<ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
|
||||||
</Centered>}
|
</Centered>}
|
||||||
@ -98,8 +98,8 @@ function BackupLayout(props: TransactionLayoutProps): JSX.Element {
|
|||||||
<div style={{ color: !props.active ? "grey" : undefined }}>
|
<div style={{ color: !props.active ? "grey" : undefined }}>
|
||||||
<a href={Pages.provider_detail.replace(':pid', encodeURIComponent(props.id))}><span>{props.title}</span></a>
|
<a href={Pages.provider_detail.replace(':pid', encodeURIComponent(props.id))}><span>{props.title}</span></a>
|
||||||
|
|
||||||
{dateStr && <SmallText style={{marginTop: 5}}>Last synced: {dateStr}</SmallText>}
|
{dateStr && <SmallText style={{ marginTop: 5 }}>Last synced: {dateStr}</SmallText>}
|
||||||
{!dateStr && <SmallLightText style={{marginTop: 5}}>Not synced</SmallLightText>}
|
{!dateStr && <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{props.status?.type === 'paid' ?
|
{props.status?.type === 'paid' ?
|
||||||
|
@ -19,21 +19,24 @@ import {
|
|||||||
Balance, BalancesResponse,
|
Balance, BalancesResponse,
|
||||||
i18n
|
i18n
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { JSX, h } from "preact";
|
import { JSX } from "preact";
|
||||||
import { WalletBox, Centered } from "../components/styled/index";
|
import { ButtonPrimary, Centered, WalletBox } from "../components/styled/index";
|
||||||
import { BalancesHook, useBalances } from "../hooks/useBalances";
|
import { BalancesHook, useBalances } from "../hooks/useBalances";
|
||||||
import { PageLink, renderAmount } from "../renderHtml";
|
import { PageLink, renderAmount } from "../renderHtml";
|
||||||
|
|
||||||
|
|
||||||
export function BalancePage() {
|
export function BalancePage({ goToWalletManualWithdraw }: { goToWalletManualWithdraw: () => void }) {
|
||||||
const balance = useBalances()
|
const balance = useBalances()
|
||||||
return <BalanceView balance={balance} Linker={PageLink} />
|
return <BalanceView balance={balance} Linker={PageLink} goToWalletManualWithdraw={goToWalletManualWithdraw} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BalanceViewProps {
|
export interface BalanceViewProps {
|
||||||
balance: BalancesHook,
|
balance: BalancesHook;
|
||||||
Linker: typeof PageLink,
|
Linker: typeof PageLink;
|
||||||
|
goToWalletManualWithdraw: () => void;
|
||||||
}
|
}
|
||||||
export function BalanceView({ balance, Linker }: BalanceViewProps) {
|
|
||||||
|
export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) {
|
||||||
if (!balance) {
|
if (!balance) {
|
||||||
return <span />
|
return <span />
|
||||||
}
|
}
|
||||||
@ -57,7 +60,9 @@ export function BalanceView({ balance, Linker }: BalanceViewProps) {
|
|||||||
</i18n.Translate></p>
|
</i18n.Translate></p>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
return <ShowBalances wallet={balance.response} />
|
return <ShowBalances wallet={balance.response}
|
||||||
|
onWithdraw={goToWalletManualWithdraw}
|
||||||
|
/>
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatPending(entry: Balance): JSX.Element {
|
function formatPending(entry: Balance): JSX.Element {
|
||||||
@ -96,7 +101,7 @@ function formatPending(entry: Balance): JSX.Element {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function ShowBalances({ wallet }: { wallet: BalancesResponse }) {
|
function ShowBalances({ wallet, onWithdraw }: { wallet: BalancesResponse, onWithdraw: () => void }) {
|
||||||
return <WalletBox>
|
return <WalletBox>
|
||||||
<section>
|
<section>
|
||||||
<Centered>{wallet.balances.map((entry) => {
|
<Centered>{wallet.balances.map((entry) => {
|
||||||
@ -113,5 +118,9 @@ function ShowBalances({ wallet }: { wallet: BalancesResponse }) {
|
|||||||
);
|
);
|
||||||
})}</Centered>
|
})}</Centered>
|
||||||
</section>
|
</section>
|
||||||
|
<footer>
|
||||||
|
<div />
|
||||||
|
<ButtonPrimary onClick={onWithdraw} >Withdraw</ButtonPrimary>
|
||||||
|
</footer>
|
||||||
</WalletBox>
|
</WalletBox>
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2021 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU 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.
|
||||||
|
|
||||||
|
GNU 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
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createExample } from '../test-utils';
|
||||||
|
import { CreateManualWithdraw as TestedComponent } from './CreateManualWithdraw';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'wallet/manual withdraw/creation',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const InitialState = createExample(TestedComponent, {
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithExchangeFilled = createExample(TestedComponent, {
|
||||||
|
currency: 'COL',
|
||||||
|
initialExchange: 'http://exchange.taler:8081',
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithExchangeAndAmountFilled = createExample(TestedComponent, {
|
||||||
|
currency: 'COL',
|
||||||
|
initialExchange: 'http://exchange.taler:8081',
|
||||||
|
initialAmount: '10'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithExchangeError = createExample(TestedComponent, {
|
||||||
|
initialExchange: 'http://exchange.tal',
|
||||||
|
error: 'The exchange url seems invalid'
|
||||||
|
});
|
||||||
|
|
||||||
|
export const WithAmountError = createExample(TestedComponent, {
|
||||||
|
currency: 'COL',
|
||||||
|
initialExchange: 'http://exchange.taler:8081',
|
||||||
|
initialAmount: 'e'
|
||||||
|
});
|
@ -0,0 +1,57 @@
|
|||||||
|
import { AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||||
|
import { VNode } from "preact";
|
||||||
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
|
import { ErrorMessage } from "../components/ErrorMessage";
|
||||||
|
import { ButtonPrimary, Input, InputWithLabel, LightText, WalletBox } from "../components/styled";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
error: string | undefined;
|
||||||
|
currency: string | undefined;
|
||||||
|
initialExchange?: string;
|
||||||
|
initialAmount?: string;
|
||||||
|
onExchangeChange: (exchange: string) => void;
|
||||||
|
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CreateManualWithdraw({ onExchangeChange, initialExchange, initialAmount, error, currency, onCreate }: Props): VNode {
|
||||||
|
const [exchange, setExchange] = useState(initialExchange || "");
|
||||||
|
const [amount, setAmount] = useState(initialAmount || "");
|
||||||
|
const parsedAmount = Amounts.parse(`${currency}:${amount}`)
|
||||||
|
|
||||||
|
let timeout = useRef<number | undefined>(undefined);
|
||||||
|
useEffect(() => {
|
||||||
|
if (timeout) window.clearTimeout(timeout.current)
|
||||||
|
timeout.current = window.setTimeout(async () => {
|
||||||
|
onExchangeChange(exchange)
|
||||||
|
}, 1000);
|
||||||
|
}, [exchange])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WalletBox>
|
||||||
|
<section>
|
||||||
|
<ErrorMessage title={error && "Can't create the reserve"} description={error} />
|
||||||
|
<h2>Manual Withdrawal</h2>
|
||||||
|
<LightText>Choose a exchange to create a reserve and then fill the reserve to withdraw the coins</LightText>
|
||||||
|
<p>
|
||||||
|
<Input invalid={!!exchange && !currency}>
|
||||||
|
<label>Exchange</label>
|
||||||
|
<input type="text" placeholder="https://" value={exchange} onChange={(e) => setExchange(e.currentTarget.value)} />
|
||||||
|
<small>http://exchange.taler:8081</small>
|
||||||
|
</Input>
|
||||||
|
{currency && <InputWithLabel invalid={!!amount && !parsedAmount}>
|
||||||
|
<label>Amount</label>
|
||||||
|
<div>
|
||||||
|
<div>{currency}</div>
|
||||||
|
<input type="number" style={{ paddingLeft: `${currency.length}em` }} value={amount} onChange={e => setAmount(e.currentTarget.value)} />
|
||||||
|
</div>
|
||||||
|
</InputWithLabel>}
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
<footer>
|
||||||
|
<div />
|
||||||
|
<ButtonPrimary disabled={!parsedAmount || !exchange} onClick={() => onCreate(exchange, parsedAmount!)}>Create</ButtonPrimary>
|
||||||
|
</footer>
|
||||||
|
</WalletBox>
|
||||||
|
);
|
||||||
|
}
|
@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
This file is part of TALER
|
||||||
|
(C) 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/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import { VNode } from "preact";
|
||||||
|
import { useEffect, useRef, useState } from "preact/hooks";
|
||||||
|
import { CreateManualWithdraw } from "./CreateManualWithdraw";
|
||||||
|
import * as wxApi from '../wxApi'
|
||||||
|
import { AcceptManualWithdrawalResult, AmountJson, Amounts } from "@gnu-taler/taler-util";
|
||||||
|
import { ReserveCreated } from "./ReserveCreated.js";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ManualWithdrawPage({ }: Props): VNode {
|
||||||
|
const [success, setSuccess] = useState<AcceptManualWithdrawalResult | undefined>(undefined)
|
||||||
|
const [currency, setCurrency] = useState<string | undefined>(undefined)
|
||||||
|
const [error, setError] = useState<string | undefined>(undefined)
|
||||||
|
|
||||||
|
async function onExchangeChange(exchange: string | undefined) {
|
||||||
|
if (!exchange) return
|
||||||
|
try {
|
||||||
|
const r = await fetch(`${exchange}/keys`)
|
||||||
|
const j = await r.json()
|
||||||
|
setCurrency(j.currency)
|
||||||
|
} catch (e) {
|
||||||
|
setError('The exchange url seems invalid')
|
||||||
|
setCurrency(undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function doCreate(exchangeBaseUrl: string, amount: AmountJson) {
|
||||||
|
try {
|
||||||
|
const resp = await wxApi.acceptManualWithdrawal(exchangeBaseUrl, Amounts.stringify(amount))
|
||||||
|
setSuccess(resp)
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
|
setError(e.message)
|
||||||
|
} else {
|
||||||
|
setError('unexpected error')
|
||||||
|
}
|
||||||
|
setSuccess(undefined)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
return <ReserveCreated reservePub={success.reservePub} paytos={success.exchangePaytoUris} onBack={() => {}}/>
|
||||||
|
}
|
||||||
|
|
||||||
|
return <CreateManualWithdraw
|
||||||
|
error={error} currency={currency}
|
||||||
|
onCreate={doCreate} onExchangeChange={onExchangeChange}
|
||||||
|
/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
This file is part of GNU Taler
|
||||||
|
(C) 2021 Taler Systems S.A.
|
||||||
|
|
||||||
|
GNU 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.
|
||||||
|
|
||||||
|
GNU 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
|
||||||
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author Sebastian Javier Marchano (sebasjm)
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { createExample } from '../test-utils';
|
||||||
|
import { ReserveCreated as TestedComponent } from './ReserveCreated';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'wallet/manual withdraw/reserve created',
|
||||||
|
component: TestedComponent,
|
||||||
|
argTypes: {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const InitialState = createExample(TestedComponent, {
|
||||||
|
reservePub: 'ASLKDJQWLKEJASLKDJSADLKASJDLKSADJ',
|
||||||
|
paytos: [
|
||||||
|
'payto://x-taler-bank/bank.taler:5882/exchangeminator?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG',
|
||||||
|
'payto://x-taler-bank/international-bank.com/myaccount?amount=COL%3A1&message=Taler+Withdrawal+TYQTE7VA4M9GZQ4TR06YBNGA05AJGMFNSK4Q62NXR2FKNDB1J4EX',
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
@ -0,0 +1,41 @@
|
|||||||
|
import { Fragment, VNode } from "preact";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import { QR } from "../components/QR";
|
||||||
|
import { ButtonBox, FontIcon, WalletBox } from "../components/styled";
|
||||||
|
|
||||||
|
export interface Props {
|
||||||
|
reservePub: string;
|
||||||
|
paytos: string[];
|
||||||
|
onBack: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ReserveCreated({ reservePub, paytos, onBack }: Props): VNode {
|
||||||
|
const [opened, setOpened] = useState(-1)
|
||||||
|
return (
|
||||||
|
<WalletBox>
|
||||||
|
<section>
|
||||||
|
<h2>Reserve created!</h2>
|
||||||
|
<p>Now you need to send money to the exchange to one of the following accounts</p>
|
||||||
|
<p>To complete the setup of the reserve, you must now initiate a wire transfer using the given wire transfer subject and crediting the specified amount to the indicated account of the exchange.</p>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{paytos.map((href, idx) => {
|
||||||
|
const url = new URL(href)
|
||||||
|
return <li key={idx}><p>
|
||||||
|
<a href="" onClick={(e) => { setOpened(o => o === idx ? -1 : idx); e.preventDefault() }}>{url.pathname}</a>
|
||||||
|
{opened === idx && <Fragment>
|
||||||
|
<p>If your system supports RFC 8905, you can do this by opening <a href={href}>this URI</a> or scan the QR with your wallet</p>
|
||||||
|
<QR text={href} />
|
||||||
|
</Fragment>}
|
||||||
|
</p></li>
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<footer>
|
||||||
|
<ButtonBox onClick={onBack}><FontIcon>←</FontIcon></ButtonBox>
|
||||||
|
<div />
|
||||||
|
</footer>
|
||||||
|
</WalletBox>
|
||||||
|
);
|
||||||
|
}
|
@ -51,7 +51,7 @@ export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
|
|||||||
transaction={transaction}
|
transaction={transaction}
|
||||||
onDelete={() => wxApi.deleteTransaction(tid).then(_ => history.go(-1))}
|
onDelete={() => wxApi.deleteTransaction(tid).then(_ => history.go(-1))}
|
||||||
onRetry={() => wxApi.retryTransaction(tid).then(_ => history.go(-1))}
|
onRetry={() => wxApi.retryTransaction(tid).then(_ => history.go(-1))}
|
||||||
onBack={() => { history.go(-1); }} />;
|
onBack={() => { route(Pages.history) }} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface WalletTransactionProps {
|
export interface WalletTransactionProps {
|
||||||
|
@ -41,6 +41,8 @@ import { SettingsPage } from "./wallet/Settings";
|
|||||||
import { TransactionPage } from './wallet/Transaction';
|
import { TransactionPage } from './wallet/Transaction';
|
||||||
import { WelcomePage } from "./wallet/Welcome";
|
import { WelcomePage } from "./wallet/Welcome";
|
||||||
import { BackupPage } from './wallet/BackupPage';
|
import { BackupPage } from './wallet/BackupPage';
|
||||||
|
import { DeveloperPage } from "./popup/Debug.js";
|
||||||
|
import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage.js";
|
||||||
|
|
||||||
|
|
||||||
function main(): void {
|
function main(): void {
|
||||||
@ -52,7 +54,9 @@ function main(): void {
|
|||||||
render(<Application />, container);
|
render(<Application />, container);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("got error", e);
|
console.error("got error", e);
|
||||||
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
|
if (e instanceof Error) {
|
||||||
|
document.body.innerText = `Fatal error: "${e.message}". Please report this bug at https://bugs.gnunet.org/.`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,10 +69,10 @@ if (document.readyState === "loading") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function withLogoAndNavBar(Component: any) {
|
function withLogoAndNavBar(Component: any) {
|
||||||
return () => <Fragment>
|
return (props: any) => <Fragment>
|
||||||
<LogoHeader />
|
<LogoHeader />
|
||||||
<WalletNavBar />
|
<WalletNavBar />
|
||||||
<Component />
|
<Component {...props} />
|
||||||
</Fragment>
|
</Fragment>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,14 +85,20 @@ function Application() {
|
|||||||
|
|
||||||
<Route path={Pages.history} component={withLogoAndNavBar(HistoryPage)} />
|
<Route path={Pages.history} component={withLogoAndNavBar(HistoryPage)} />
|
||||||
<Route path={Pages.transaction} component={withLogoAndNavBar(TransactionPage)} />
|
<Route path={Pages.transaction} component={withLogoAndNavBar(TransactionPage)} />
|
||||||
<Route path={Pages.balance} component={withLogoAndNavBar(BalancePage)} />
|
<Route path={Pages.balance} component={withLogoAndNavBar(BalancePage)}
|
||||||
|
goToWalletManualWithdraw={() => route(Pages.manual_withdraw)}
|
||||||
|
/>
|
||||||
<Route path={Pages.settings} component={withLogoAndNavBar(SettingsPage)} />
|
<Route path={Pages.settings} component={withLogoAndNavBar(SettingsPage)} />
|
||||||
<Route path={Pages.backup} component={withLogoAndNavBar(BackupPage)} />
|
<Route path={Pages.backup} component={withLogoAndNavBar(BackupPage)} />
|
||||||
|
|
||||||
|
<Route path={Pages.manual_withdraw} component={withLogoAndNavBar(ManualWithdrawPage)} />
|
||||||
|
|
||||||
<Route path={Pages.reset_required} component={() => <div>no yet implemented</div>} />
|
<Route path={Pages.reset_required} component={() => <div>no yet implemented</div>} />
|
||||||
<Route path={Pages.payback} component={() => <div>no yet implemented</div>} />
|
<Route path={Pages.payback} component={() => <div>no yet implemented</div>} />
|
||||||
<Route path={Pages.return_coins} component={() => <div>no yet implemented</div>} />
|
<Route path={Pages.return_coins} component={() => <div>no yet implemented</div>} />
|
||||||
|
|
||||||
|
<Route path={Pages.dev} component={withLogoAndNavBar(DeveloperPage)} />
|
||||||
|
|
||||||
{/** call to action */}
|
{/** call to action */}
|
||||||
<Route path={Pages.pay} component={PayPage} />
|
<Route path={Pages.pay} component={PayPage} />
|
||||||
<Route path={Pages.refund} component={RefundPage} />
|
<Route path={Pages.refund} component={RefundPage} />
|
||||||
|
@ -40,6 +40,9 @@ import {
|
|||||||
SetWalletDeviceIdRequest,
|
SetWalletDeviceIdRequest,
|
||||||
GetExchangeWithdrawalInfo,
|
GetExchangeWithdrawalInfo,
|
||||||
AcceptExchangeTosRequest,
|
AcceptExchangeTosRequest,
|
||||||
|
AcceptManualWithdrawalResult,
|
||||||
|
AcceptManualWithdrawalRequest,
|
||||||
|
AmountJson,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { AddBackupProviderRequest, BackupProviderState, OperationFailedError, RemoveBackupProviderRequest } from "@gnu-taler/taler-wallet-core";
|
import { AddBackupProviderRequest, BackupProviderState, OperationFailedError, RemoveBackupProviderRequest } from "@gnu-taler/taler-wallet-core";
|
||||||
import { BackupInfo } from "@gnu-taler/taler-wallet-core";
|
import { BackupInfo } from "@gnu-taler/taler-wallet-core";
|
||||||
@ -252,6 +255,21 @@ export function acceptWithdrawal(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a reserve into the exchange that expect the amount indicated
|
||||||
|
* @param exchangeBaseUrl
|
||||||
|
* @param amount
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function acceptManualWithdrawal(
|
||||||
|
exchangeBaseUrl: string,
|
||||||
|
amount: string,
|
||||||
|
): Promise<AcceptManualWithdrawalResult> {
|
||||||
|
return callBackend("acceptManualWithdrawal", {
|
||||||
|
amount, exchangeBaseUrl
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function setExchangeTosAccepted(
|
export function setExchangeTosAccepted(
|
||||||
exchangeBaseUrl: string,
|
exchangeBaseUrl: string,
|
||||||
etag: string | undefined
|
etag: string | undefined
|
||||||
|
Loading…
Reference in New Issue
Block a user