splitted rollup config for testing and first component state unit test
This commit is contained in:
parent
136c39ba9f
commit
e21c1b3192
3
packages/taler-wallet-webextension/encode.mjs
Normal file
3
packages/taler-wallet-webextension/encode.mjs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
import {encodeCrock, stringToBytes} from "../taler-util/lib/talerCrypto.js";
|
||||||
|
const pepe =process.argv[2]
|
||||||
|
console.log(pepe, encodeCrock(stringToBytes(pepe)));
|
@ -12,6 +12,7 @@
|
|||||||
"test": "mocha --enable-source-maps 'dist/**/*.test.js'",
|
"test": "mocha --enable-source-maps 'dist/**/*.test.js'",
|
||||||
"test:coverage": "nyc pnpm test",
|
"test:coverage": "nyc pnpm test",
|
||||||
"compile": "rollup -c -m",
|
"compile": "rollup -c -m",
|
||||||
|
"compile:test": "rollup -c rollup.config.test.js -m",
|
||||||
"prepare": "rollup -c -m",
|
"prepare": "rollup -c -m",
|
||||||
"build-storybook": "build-storybook",
|
"build-storybook": "build-storybook",
|
||||||
"storybook": "start-storybook -s . -p 6006 --no-open",
|
"storybook": "start-storybook -s . -p 6006 --no-open",
|
||||||
|
@ -10,30 +10,7 @@ import css from 'rollup-plugin-css-only';
|
|||||||
import ignore from "rollup-plugin-ignore";
|
import ignore from "rollup-plugin-ignore";
|
||||||
import typescript from '@rollup/plugin-typescript';
|
import typescript from '@rollup/plugin-typescript';
|
||||||
|
|
||||||
import path from 'path';
|
export const makePlugins = () => [
|
||||||
import fs from 'fs';
|
|
||||||
|
|
||||||
function fromDir(startPath, regex) {
|
|
||||||
if (!fs.existsSync(startPath)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const files = fs.readdirSync(startPath);
|
|
||||||
const result = files.flatMap(file => {
|
|
||||||
const filename = path.join(startPath, file);
|
|
||||||
|
|
||||||
const stat = fs.lstatSync(filename);
|
|
||||||
if (stat.isDirectory()) {
|
|
||||||
return fromDir(filename, regex);
|
|
||||||
}
|
|
||||||
else if (regex.test(filename)) {
|
|
||||||
return filename
|
|
||||||
}
|
|
||||||
}).filter(x => !!x)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
const makePlugins = () => [
|
|
||||||
typescript({
|
typescript({
|
||||||
outputToFilesystem: false,
|
outputToFilesystem: false,
|
||||||
}),
|
}),
|
||||||
@ -135,26 +112,10 @@ const webExtensionCryptoWorker = {
|
|||||||
plugins: makePlugins(),
|
plugins: makePlugins(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const tests = fromDir('./src', /.test.ts$/).map(test => ({
|
|
||||||
input: test,
|
|
||||||
output: {
|
|
||||||
file: test.replace(/^src/, 'dist').replace(/\.ts$/, '.js'),
|
|
||||||
format: "iife",
|
|
||||||
exports: "none",
|
|
||||||
name: test,
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
...makePlugins(),
|
|
||||||
css({
|
|
||||||
output: 'walletEntryPoint.css',
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}))
|
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
webExtensionPopupEntryPoint,
|
webExtensionPopupEntryPoint,
|
||||||
webExtensionWalletEntryPoint,
|
webExtensionWalletEntryPoint,
|
||||||
webExtensionBackgroundPageScript,
|
webExtensionBackgroundPageScript,
|
||||||
webExtensionCryptoWorker,
|
webExtensionCryptoWorker,
|
||||||
...tests,
|
|
||||||
];
|
];
|
||||||
|
47
packages/taler-wallet-webextension/rollup.config.test.js
Normal file
47
packages/taler-wallet-webextension/rollup.config.test.js
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// rollup.config.js
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import css from 'rollup-plugin-css-only';
|
||||||
|
import { makePlugins } from "./rollup.config"
|
||||||
|
|
||||||
|
function fromDir(startPath, regex) {
|
||||||
|
if (!fs.existsSync(startPath)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const files = fs.readdirSync(startPath);
|
||||||
|
const result = files.flatMap(file => {
|
||||||
|
const filename = path.join(startPath, file);
|
||||||
|
|
||||||
|
const stat = fs.lstatSync(filename);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
return fromDir(filename, regex);
|
||||||
|
}
|
||||||
|
else if (regex.test(filename)) {
|
||||||
|
return filename
|
||||||
|
}
|
||||||
|
}).filter(x => !!x)
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
const tests = fromDir('./src', /.test.ts$/)
|
||||||
|
.filter(t => t === 'src/wallet/CreateManualWithdraw.test.ts')
|
||||||
|
.map(test => ({
|
||||||
|
input: test,
|
||||||
|
output: {
|
||||||
|
file: test.replace(/^src/, 'dist').replace(/\.ts$/, '.js'),
|
||||||
|
format: "iife",
|
||||||
|
exports: "none",
|
||||||
|
name: test,
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
...makePlugins(),
|
||||||
|
css({
|
||||||
|
output: 'walletEntryPoint.css',
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}))
|
||||||
|
|
||||||
|
export default [
|
||||||
|
...tests,
|
||||||
|
];
|
@ -0,0 +1,14 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="manifest" href="./manifest.json" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="./static/popup.html" name="popup" width="500" height="400">
|
||||||
|
algo
|
||||||
|
</iframe>
|
||||||
|
<hr />
|
||||||
|
<iframe src="./static/wallet.html" name="wallet" width="800" height="100%">
|
||||||
|
otroe
|
||||||
|
</iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -14,7 +14,7 @@
|
|||||||
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
|
||||||
*/
|
*/
|
||||||
import { useTalerActionURL } from "./useTalerActionURL"
|
import { useTalerActionURL } from "./useTalerActionURL"
|
||||||
import { justBrowser_it, mountBrowser } from "../test-utils";
|
import { mountHook } from "../test-utils";
|
||||||
import { IoCProviderForTesting } from "../context/iocContext";
|
import { IoCProviderForTesting } from "../context/iocContext";
|
||||||
import { h, VNode } from "preact";
|
import { h, VNode } from "preact";
|
||||||
import { act } from "preact/test-utils";
|
import { act } from "preact/test-utils";
|
||||||
@ -22,7 +22,7 @@ import { act } from "preact/test-utils";
|
|||||||
describe('useTalerActionURL hook', () => {
|
describe('useTalerActionURL hook', () => {
|
||||||
|
|
||||||
// eslint-disable-next-line jest/expect-expect
|
// eslint-disable-next-line jest/expect-expect
|
||||||
justBrowser_it('should be set url to undefined when dismiss', async () => {
|
it('should be set url to undefined when dismiss', async () => {
|
||||||
|
|
||||||
const ctx = ({ children }: { children: any }): VNode => {
|
const ctx = ({ children }: { children: any }): VNode => {
|
||||||
return h(IoCProviderForTesting, {
|
return h(IoCProviderForTesting, {
|
||||||
@ -32,7 +32,7 @@ describe('useTalerActionURL hook', () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const { result, waitNextUpdate } = mountBrowser(useTalerActionURL, ctx)
|
const { result, waitNextUpdate } = mountHook(useTalerActionURL, ctx)
|
||||||
|
|
||||||
{
|
{
|
||||||
const [url] = result.current!
|
const [url] = result.current!
|
||||||
|
@ -31,7 +31,6 @@ function testThisStory(st: any): any {
|
|||||||
const Component = (st as any)[k];
|
const Component = (st as any)[k];
|
||||||
if (k === "default" || !Component) return;
|
if (k === "default" || !Component) return;
|
||||||
|
|
||||||
|
|
||||||
// eslint-disable-next-line jest/expect-expect
|
// eslint-disable-next-line jest/expect-expect
|
||||||
it(`example: ${k}`, () => {
|
it(`example: ${k}`, () => {
|
||||||
renderNodeOrBrowser(Component, Component.args);
|
renderNodeOrBrowser(Component, Component.args);
|
||||||
|
@ -62,7 +62,9 @@ interface Mounted<T> {
|
|||||||
waitNextUpdate: () => Promise<void>;
|
waitNextUpdate: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mountBrowser<T>(callback: () => T, Context?: ({ children }: { children: any }) => VNode): Mounted<T> {
|
const isNode = typeof window === "undefined"
|
||||||
|
|
||||||
|
export function mountHook<T>(callback: () => T, Context?: ({ children }: { children: any }) => VNode): Mounted<T> {
|
||||||
const result: { current: T | null } = {
|
const result: { current: T | null } = {
|
||||||
current: null
|
current: null
|
||||||
}
|
}
|
||||||
@ -81,23 +83,6 @@ export function mountBrowser<T>(callback: () => T, Context?: ({ children }: { ch
|
|||||||
// create the vdom with context if required
|
// create the vdom with context if required
|
||||||
const vdom = !Context ? create(Component, {}) : create(Context, { children: [create(Component, {})] },);
|
const vdom = !Context ? create(Component, {}) : create(Context, { children: [create(Component, {})] },);
|
||||||
|
|
||||||
// in non-browser environment (server side rendering) just serialize to
|
|
||||||
// string and exit
|
|
||||||
if (typeof window === "undefined") {
|
|
||||||
renderToString(vdom);
|
|
||||||
return { unmount: () => null, result } as any
|
|
||||||
}
|
|
||||||
|
|
||||||
// do the render into the DOM
|
|
||||||
const div = document.createElement("div");
|
|
||||||
document.body.appendChild(div);
|
|
||||||
renderIntoDom(vdom, div);
|
|
||||||
|
|
||||||
// clean up callback
|
|
||||||
function unmount(): any {
|
|
||||||
document.body.removeChild(div);
|
|
||||||
}
|
|
||||||
|
|
||||||
// waiter callback
|
// waiter callback
|
||||||
async function waitNextUpdate(): Promise<void> {
|
async function waitNextUpdate(): Promise<void> {
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
@ -112,11 +97,22 @@ export function mountBrowser<T>(callback: () => T, Context?: ({ children }: { ch
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customElement = {} as Element
|
||||||
|
const parentElement = isNode ? customElement : document.createElement("div");
|
||||||
|
if (!isNode) {
|
||||||
|
document.body.appendChild(parentElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderIntoDom(vdom, parentElement);
|
||||||
|
|
||||||
|
// clean up callback
|
||||||
|
function unmount() {
|
||||||
|
if (!isNode) {
|
||||||
|
document.body.removeChild(parentElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
unmount, result, waitNextUpdate
|
unmount, result, waitNextUpdate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const nullTestFunction = {} as TestFunction
|
|
||||||
export const justBrowser_it: PendingTestFunction | TestFunction =
|
|
||||||
typeof it === 'undefined' ? nullTestFunction : (typeof window === 'undefined' ? it.skip : it)
|
|
@ -29,30 +29,30 @@ export default {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// ,
|
// ,
|
||||||
const exchangeList = {
|
const exchangeUrlWithCurrency = {
|
||||||
"http://exchange.taler:8081": "COL",
|
"http://exchange.taler:8081": "COL",
|
||||||
"http://exchange.tal": "EUR",
|
"http://exchange.tal": "EUR",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WithoutAnyExchangeKnown = createExample(TestedComponent, {
|
export const WithoutAnyExchangeKnown = createExample(TestedComponent, {
|
||||||
exchangeList: {},
|
exchangeUrlWithCurrency: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const InitialState = createExample(TestedComponent, {
|
export const InitialState = createExample(TestedComponent, {
|
||||||
exchangeList,
|
exchangeUrlWithCurrency,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WithAmountInitialized = createExample(TestedComponent, {
|
export const WithAmountInitialized = createExample(TestedComponent, {
|
||||||
initialAmount: "10",
|
initialAmount: "10",
|
||||||
exchangeList,
|
exchangeUrlWithCurrency,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WithExchangeError = createExample(TestedComponent, {
|
export const WithExchangeError = createExample(TestedComponent, {
|
||||||
error: "The exchange url seems invalid",
|
error: "The exchange url seems invalid",
|
||||||
exchangeList,
|
exchangeUrlWithCurrency,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WithAmountError = createExample(TestedComponent, {
|
export const WithAmountError = createExample(TestedComponent, {
|
||||||
initialAmount: "e",
|
initialAmount: "e",
|
||||||
exchangeList,
|
exchangeUrlWithCurrency,
|
||||||
});
|
});
|
||||||
|
@ -0,0 +1,212 @@
|
|||||||
|
/*
|
||||||
|
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 { SelectFieldHandler, TextFieldHandler, useComponentState } from "./CreateManualWithdraw";
|
||||||
|
import { expect } from "chai";
|
||||||
|
import { mountHook } from "../test-utils";
|
||||||
|
|
||||||
|
|
||||||
|
const exchangeListWithARSandUSD = {
|
||||||
|
"url1": "USD",
|
||||||
|
"url2": "ARS",
|
||||||
|
"url3": "ARS",
|
||||||
|
};
|
||||||
|
|
||||||
|
const exchangeListEmpty = {
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("CreateManualWithdraw states", () => {
|
||||||
|
it("should set noExchangeFound when exchange list is empty", () => {
|
||||||
|
const { result } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListEmpty, undefined, undefined),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect(result.current).not.to.be.undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.noExchangeFound).equal(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set noExchangeFound when exchange list doesn't include selected currency", () => {
|
||||||
|
const { result } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "COL"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect(result.current).not.to.be.undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.noExchangeFound).equal(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it("should select the first exchange from the list", () => {
|
||||||
|
const { result } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, undefined),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect(result.current).not.to.be.undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url1")
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should select the first exchange with the selected currency", () => {
|
||||||
|
const { result } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect(result.current).not.to.be.undefined;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url2")
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change the exchange when currency change", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url2")
|
||||||
|
|
||||||
|
result.current.currency.onChange("USD")
|
||||||
|
|
||||||
|
await waitNextUpdate()
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url1")
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should change the currency when exchange change", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url2")
|
||||||
|
expect(result.current.currency.value).equal("ARS")
|
||||||
|
|
||||||
|
result.current.exchange.onChange("url1")
|
||||||
|
|
||||||
|
await waitNextUpdate()
|
||||||
|
|
||||||
|
expect(result.current.exchange.value).equal("url1")
|
||||||
|
expect(result.current.currency.value).equal("USD")
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should update parsed amount when amount change", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(result.current.parsedAmount).equal(undefined)
|
||||||
|
|
||||||
|
result.current.amount.onInput("12")
|
||||||
|
|
||||||
|
await waitNextUpdate()
|
||||||
|
|
||||||
|
expect(result.current.parsedAmount).deep.equals({
|
||||||
|
value: 12, fraction: 0, currency: "ARS"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should have an amount field", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
await defaultTestForInputText(waitNextUpdate, () => result.current!.amount)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have an exchange selector ", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
await defaultTestForInputSelect(waitNextUpdate, () => result.current!.exchange)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should have a currency selector ", async () => {
|
||||||
|
const { result, waitNextUpdate } = mountHook(() =>
|
||||||
|
useComponentState(exchangeListWithARSandUSD, undefined, "ARS"),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result.current) {
|
||||||
|
expect.fail("hook didn't render");
|
||||||
|
}
|
||||||
|
|
||||||
|
await defaultTestForInputSelect(waitNextUpdate, () => result.current!.currency)
|
||||||
|
})
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
async function defaultTestForInputText(awaiter: () => Promise<void>, getField: () => TextFieldHandler) {
|
||||||
|
const initialValue = getField().value;
|
||||||
|
const otherValue = `${initialValue} something else`
|
||||||
|
getField().onInput(otherValue)
|
||||||
|
|
||||||
|
await awaiter()
|
||||||
|
|
||||||
|
expect(getField().value).equal(otherValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function defaultTestForInputSelect(awaiter: () => Promise<void>, getField: () => SelectFieldHandler) {
|
||||||
|
const initialValue = getField().value;
|
||||||
|
const keys = Object.keys(getField().list)
|
||||||
|
const nextIdx = keys.indexOf(initialValue) + 1
|
||||||
|
if (keys.length < nextIdx) {
|
||||||
|
throw new Error('no enough values')
|
||||||
|
}
|
||||||
|
const nextValue = keys[nextIdx]
|
||||||
|
getField().onChange(nextValue)
|
||||||
|
|
||||||
|
await awaiter()
|
||||||
|
|
||||||
|
expect(getField().value).equal(nextValue)
|
||||||
|
}
|
@ -39,20 +39,39 @@ import { Pages } from "../NavigationBar";
|
|||||||
export interface Props {
|
export interface Props {
|
||||||
error: string | undefined;
|
error: string | undefined;
|
||||||
initialAmount?: string;
|
initialAmount?: string;
|
||||||
exchangeList: Record<string, string>;
|
exchangeUrlWithCurrency: Record<string, string>;
|
||||||
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
|
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
|
||||||
initialCurrency?: string;
|
initialCurrency?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface State {
|
||||||
|
noExchangeFound: boolean;
|
||||||
|
parsedAmount: AmountJson | undefined;
|
||||||
|
amount: TextFieldHandler;
|
||||||
|
currency: SelectFieldHandler;
|
||||||
|
exchange: SelectFieldHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TextFieldHandler {
|
||||||
|
onInput: (value: string) => void;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SelectFieldHandler {
|
||||||
|
onChange: (value: string) => void;
|
||||||
|
value: string;
|
||||||
|
list: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
export function useComponentState(
|
export function useComponentState(
|
||||||
exchangeList: Record<string, string>,
|
exchangeUrlWithCurrency: Record<string, string>,
|
||||||
initialAmount: string | undefined,
|
initialAmount: string | undefined,
|
||||||
initialCurrency: string | undefined,
|
initialCurrency: string | undefined,
|
||||||
) {
|
): State {
|
||||||
const exchangeSelectList = Object.keys(exchangeList);
|
const exchangeSelectList = Object.keys(exchangeUrlWithCurrency);
|
||||||
const currencySelectList = Object.values(exchangeList);
|
const currencySelectList = Object.values(exchangeUrlWithCurrency);
|
||||||
const exchangeMap = exchangeSelectList.reduce(
|
const exchangeMap = exchangeSelectList.reduce(
|
||||||
(p, c) => ({ ...p, [c]: `${c} (${exchangeList[c]})` }),
|
(p, c) => ({ ...p, [c]: `${c} (${exchangeUrlWithCurrency[c]})` }),
|
||||||
{} as Record<string, string>,
|
{} as Record<string, string>,
|
||||||
);
|
);
|
||||||
const currencyMap = currencySelectList.reduce(
|
const currencyMap = currencySelectList.reduce(
|
||||||
@ -61,7 +80,7 @@ export function useComponentState(
|
|||||||
);
|
);
|
||||||
|
|
||||||
const foundExchangeForCurrency = exchangeSelectList.findIndex(
|
const foundExchangeForCurrency = exchangeSelectList.findIndex(
|
||||||
(e) => exchangeList[e] === initialCurrency,
|
(e) => exchangeUrlWithCurrency[e] === initialCurrency,
|
||||||
);
|
);
|
||||||
|
|
||||||
const initialExchange =
|
const initialExchange =
|
||||||
@ -73,7 +92,7 @@ export function useComponentState(
|
|||||||
|
|
||||||
const [exchange, setExchange] = useState(initialExchange || "");
|
const [exchange, setExchange] = useState(initialExchange || "");
|
||||||
const [currency, setCurrency] = useState(
|
const [currency, setCurrency] = useState(
|
||||||
initialExchange ? exchangeList[initialExchange] : "",
|
initialExchange ? exchangeUrlWithCurrency[initialExchange] : "",
|
||||||
);
|
);
|
||||||
|
|
||||||
const [amount, setAmount] = useState(initialAmount || "");
|
const [amount, setAmount] = useState(initialAmount || "");
|
||||||
@ -81,12 +100,14 @@ export function useComponentState(
|
|||||||
|
|
||||||
function changeExchange(exchange: string): void {
|
function changeExchange(exchange: string): void {
|
||||||
setExchange(exchange);
|
setExchange(exchange);
|
||||||
setCurrency(exchangeList[exchange]);
|
setCurrency(exchangeUrlWithCurrency[exchange]);
|
||||||
}
|
}
|
||||||
|
|
||||||
function changeCurrency(currency: string): void {
|
function changeCurrency(currency: string): void {
|
||||||
setCurrency(currency);
|
setCurrency(currency);
|
||||||
const found = Object.entries(exchangeList).find((e) => e[1] === currency);
|
const found = Object.entries(exchangeUrlWithCurrency).find(
|
||||||
|
(e) => e[1] === currency,
|
||||||
|
);
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
setExchange(found[0]);
|
setExchange(found[0]);
|
||||||
@ -95,7 +116,7 @@ export function useComponentState(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
initialExchange,
|
noExchangeFound: initialExchange === undefined,
|
||||||
currency: {
|
currency: {
|
||||||
list: currencyMap,
|
list: currencyMap,
|
||||||
value: currency,
|
value: currency,
|
||||||
@ -114,12 +135,12 @@ export function useComponentState(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
interface InputHandler {
|
export interface InputHandler {
|
||||||
value: string;
|
value: string;
|
||||||
onInput: (s: string) => void;
|
onInput: (s: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SelectInputHandler {
|
export interface SelectInputHandler {
|
||||||
list: Record<string, string>;
|
list: Record<string, string>;
|
||||||
value: string;
|
value: string;
|
||||||
onChange: (s: string) => void;
|
onChange: (s: string) => void;
|
||||||
@ -127,16 +148,20 @@ interface SelectInputHandler {
|
|||||||
|
|
||||||
export function CreateManualWithdraw({
|
export function CreateManualWithdraw({
|
||||||
initialAmount,
|
initialAmount,
|
||||||
exchangeList,
|
exchangeUrlWithCurrency,
|
||||||
error,
|
error,
|
||||||
initialCurrency,
|
initialCurrency,
|
||||||
onCreate,
|
onCreate,
|
||||||
}: Props): VNode {
|
}: Props): VNode {
|
||||||
const { i18n } = useTranslationContext();
|
const { i18n } = useTranslationContext();
|
||||||
|
|
||||||
const state = useComponentState(exchangeList, initialAmount, initialCurrency);
|
const state = useComponentState(
|
||||||
|
exchangeUrlWithCurrency,
|
||||||
|
initialAmount,
|
||||||
|
initialCurrency,
|
||||||
|
);
|
||||||
|
|
||||||
if (!state.initialExchange) {
|
if (state.noExchangeFound) {
|
||||||
if (initialCurrency !== undefined) {
|
if (initialCurrency !== undefined) {
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
|
@ -110,7 +110,7 @@ export function ManualWithdrawPage({ currency, onCancel }: Props): VNode {
|
|||||||
return (
|
return (
|
||||||
<CreateManualWithdraw
|
<CreateManualWithdraw
|
||||||
error={error}
|
error={error}
|
||||||
exchangeList={exchangeList}
|
exchangeUrlWithCurrency={exchangeList}
|
||||||
onCreate={doCreate}
|
onCreate={doCreate}
|
||||||
initialCurrency={currency}
|
initialCurrency={currency}
|
||||||
/>
|
/>
|
||||||
|
@ -104,7 +104,7 @@ async function callBackend(operation: string, payload: any): Promise<any> {
|
|||||||
}
|
}
|
||||||
console.log("got response", response);
|
console.log("got response", response);
|
||||||
if (response.type === "error") {
|
if (response.type === "error") {
|
||||||
throw new TalerError.fromUncheckedDetail(response.error);
|
throw TalerError.fromUncheckedDetail(response.error);
|
||||||
}
|
}
|
||||||
return response.result;
|
return response.result;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user