summaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-11-15 11:18:58 -0300
committerSebastian <sebasjm@gmail.com>2021-11-15 11:18:58 -0300
commit1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5 (patch)
tree99e8241a5eb5af4d752be93a460004bc0c6255aa /packages/taler-wallet-webextension
parent9692f589c687a2ba39a705ca4238cf123f444c61 (diff)
downloadwallet-core-1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5.tar.gz
wallet-core-1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5.tar.bz2
wallet-core-1d4815c66c395f4fcc86c30e20f3d005e3cb9ff5.zip
prettier
Diffstat (limited to 'packages/taler-wallet-webextension')
-rw-r--r--packages/taler-wallet-webextension/package.json3
-rw-r--r--packages/taler-wallet-webextension/src/NavigationBar.tsx75
-rw-r--r--packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.js35
-rw-r--r--packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.ts5
-rw-r--r--packages/taler-wallet-webextension/src/compat.js57
-rw-r--r--packages/taler-wallet-webextension/src/components/Checkbox.tsx33
-rw-r--r--packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx47
-rw-r--r--packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx13
-rw-r--r--packages/taler-wallet-webextension/src/components/Diagnostics.tsx12
-rw-r--r--packages/taler-wallet-webextension/src/components/EditableText.tsx66
-rw-r--r--packages/taler-wallet-webextension/src/components/ErrorMessage.tsx41
-rw-r--r--packages/taler-wallet-webextension/src/components/ExchangeToS.tsx86
-rw-r--r--packages/taler-wallet-webextension/src/components/LogoHeader.tsx31
-rw-r--r--packages/taler-wallet-webextension/src/components/Part.tsx28
-rw-r--r--packages/taler-wallet-webextension/src/components/QR.tsx53
-rw-r--r--packages/taler-wallet-webextension/src/components/SelectList.tsx95
-rw-r--r--packages/taler-wallet-webextension/src/components/TransactionItem.tsx76
-rw-r--r--packages/taler-wallet-webextension/src/components/styled/index.tsx219
-rw-r--r--packages/taler-wallet-webextension/src/context/devContext.ts24
-rw-r--r--packages/taler-wallet-webextension/src/context/translation.ts56
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.stories.tsx190
-rw-r--r--packages/taler-wallet-webextension/src/cta/Pay.tsx351
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.stories.tsx72
-rw-r--r--packages/taler-wallet-webextension/src/cta/Refund.tsx53
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip.stories.tsx48
-rw-r--r--packages/taler-wallet-webextension/src/cta/Tip.tsx44
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx542
-rw-r--r--packages/taler-wallet-webextension/src/cta/Withdraw.tsx500
-rw-r--r--packages/taler-wallet-webextension/src/cta/payback.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/cta/reset-required.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/cta/return-coins.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/custom.d.ts2
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts4
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts25
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useBackupStatus.ts50
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useBalances.ts3
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts6
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts9
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useLang.ts13
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts44
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts4
-rw-r--r--packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts9
-rw-r--r--packages/taler-wallet-webextension/src/i18n/strings.ts2
-rw-r--r--packages/taler-wallet-webextension/src/popup/Backup.stories.tsx307
-rw-r--r--packages/taler-wallet-webextension/src/popup/BackupPage.tsx176
-rw-r--r--packages/taler-wallet-webextension/src/popup/Balance.stories.tsx253
-rw-r--r--packages/taler-wallet-webextension/src/popup/BalancePage.tsx219
-rw-r--r--packages/taler-wallet-webextension/src/popup/Debug.tsx8
-rw-r--r--packages/taler-wallet-webextension/src/popup/History.stories.tsx184
-rw-r--r--packages/taler-wallet-webextension/src/popup/History.tsx122
-rw-r--r--packages/taler-wallet-webextension/src/popup/Popup.stories.tsx29
-rw-r--r--packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx41
-rw-r--r--packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx40
-rw-r--r--packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx323
-rw-r--r--packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx269
-rw-r--r--packages/taler-wallet-webextension/src/popup/Settings.stories.tsx19
-rw-r--r--packages/taler-wallet-webextension/src/popup/Settings.tsx93
-rw-r--r--packages/taler-wallet-webextension/src/popup/TalerActionFound.stories.tsx24
-rw-r--r--packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx161
-rw-r--r--packages/taler-wallet-webextension/src/popupEntryPoint.tsx77
-rw-r--r--packages/taler-wallet-webextension/src/renderHtml.tsx38
-rw-r--r--packages/taler-wallet-webextension/src/test-utils.ts16
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx307
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BackupPage.tsx177
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx84
-rw-r--r--packages/taler-wallet-webextension/src/wallet/BalancePage.tsx129
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx39
-rw-r--r--packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx94
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.stories.tsx198
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx103
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx92
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx41
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx40
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx323
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx269
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx25
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx54
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx32
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Settings.tsx109
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx213
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Transaction.tsx442
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx20
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Welcome.tsx76
-rw-r--r--packages/taler-wallet-webextension/src/walletEntryPoint.tsx128
-rw-r--r--packages/taler-wallet-webextension/src/wxApi.ts104
-rw-r--r--packages/taler-wallet-webextension/tsconfig.json20
86 files changed, 4970 insertions, 3580 deletions
diff --git a/packages/taler-wallet-webextension/package.json b/packages/taler-wallet-webextension/package.json
index 3a43f1e76..b3d0b10af 100644
--- a/packages/taler-wallet-webextension/package.json
+++ b/packages/taler-wallet-webextension/package.json
@@ -13,6 +13,7 @@
"compile": "tsc && rollup -c",
"build-storybook": "build-storybook",
"storybook": "start-storybook -s . -p 6006",
+ "pretty": "prettier --write src",
"watch": "tsc --watch & rollup -w -c"
},
"dependencies": {
@@ -80,4 +81,4 @@
"\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|po)$": "<rootDir>/tests/__mocks__/fileTransformer.js"
}
}
-}
+} \ No newline at end of file
diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx
index 9edd8ca67..f206fa2dd 100644
--- a/packages/taler-wallet-webextension/src/NavigationBar.tsx
+++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx
@@ -28,29 +28,29 @@ import { i18n } from "@gnu-taler/taler-util";
import { ComponentChildren, JSX, h } from "preact";
import Match from "preact-router/match";
import { useDevContext } from "./context/devContext";
-import { PopupNavigation } from './components/styled'
+import { PopupNavigation } from "./components/styled";
export enum Pages {
- welcome = '/welcome',
- balance = '/balance',
- manual_withdraw = '/manual-withdraw',
- settings = '/settings',
- dev = '/dev',
- cta = '/cta',
- backup = '/backup',
- history = '/history',
- transaction = '/transaction/:tid',
- provider_detail = '/provider/:pid',
- provider_add = '/provider/add',
+ welcome = "/welcome",
+ balance = "/balance",
+ manual_withdraw = "/manual-withdraw",
+ settings = "/settings",
+ dev = "/dev",
+ cta = "/cta",
+ backup = "/backup",
+ history = "/history",
+ transaction = "/transaction/:tid",
+ provider_detail = "/provider/:pid",
+ provider_add = "/provider/add",
- reset_required = '/reset-required',
- payback = '/payback',
- return_coins = '/return-coins',
+ reset_required = "/reset-required",
+ payback = "/payback",
+ return_coins = "/return-coins",
- pay = '/pay',
- refund = '/refund',
- tips = '/tip',
- withdraw = '/withdraw',
+ pay = "/pay",
+ refund = "/refund",
+ tips = "/tip",
+ withdraw = "/withdraw",
}
interface TabProps {
@@ -71,23 +71,28 @@ function Tab(props: TabProps): JSX.Element {
);
}
-export function NavBar({ devMode, path }: { path: string, devMode: boolean }) {
- return <PopupNavigation devMode={devMode}>
- <div>
- <Tab target="/balance" current={path}>{i18n.str`Balance`}</Tab>
- <Tab target="/history" current={path}>{i18n.str`History`}</Tab>
- <Tab target="/backup" current={path}>{i18n.str`Backup`}</Tab>
- <Tab target="/settings" current={path}>{i18n.str`Settings`}</Tab>
- {devMode && <Tab target="/dev" current={path}>{i18n.str`Dev`}</Tab>}
- </div>
- </PopupNavigation>
+export function NavBar({ devMode, path }: { path: string; devMode: boolean }) {
+ return (
+ <PopupNavigation devMode={devMode}>
+ <div>
+ <Tab target="/balance" current={path}>{i18n.str`Balance`}</Tab>
+ <Tab target="/history" current={path}>{i18n.str`History`}</Tab>
+ <Tab target="/backup" current={path}>{i18n.str`Backup`}</Tab>
+ <Tab target="/settings" current={path}>{i18n.str`Settings`}</Tab>
+ {devMode && <Tab target="/dev" current={path}>{i18n.str`Dev`}</Tab>}
+ </div>
+ </PopupNavigation>
+ );
}
export function WalletNavBar() {
- const { devMode } = useDevContext()
- return <Match>{({ path }: any) => {
- console.log("path", path)
- return <NavBar devMode={devMode} path={path} />
- }}</Match>
+ const { devMode } = useDevContext();
+ return (
+ <Match>
+ {({ path }: any) => {
+ console.log("path", path);
+ return <NavBar devMode={devMode} path={path} />;
+ }}
+ </Match>
+ );
}
-
diff --git a/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.js b/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.js
index e9492a2fb..8d958d6bd 100644
--- a/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.js
+++ b/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.js
@@ -21,24 +21,23 @@ exports.BrowserCryptoWorkerFactory = void 0;
* @author Florian Dold
*/
class BrowserCryptoWorkerFactory {
- startWorker() {
- const workerCtor = Worker;
- const workerPath = "/browserWorkerEntry.js";
- return new workerCtor(workerPath);
- }
- getConcurrency() {
- let concurrency = 2;
- try {
- // only works in the browser
- // tslint:disable-next-line:no-string-literal
- concurrency = navigator["hardwareConcurrency"];
- concurrency = Math.max(1, Math.ceil(concurrency / 2));
- }
- catch (e) {
- concurrency = 2;
- }
- return concurrency;
+ startWorker() {
+ const workerCtor = Worker;
+ const workerPath = "/browserWorkerEntry.js";
+ return new workerCtor(workerPath);
+ }
+ getConcurrency() {
+ let concurrency = 2;
+ try {
+ // only works in the browser
+ // tslint:disable-next-line:no-string-literal
+ concurrency = navigator["hardwareConcurrency"];
+ concurrency = Math.max(1, Math.ceil(concurrency / 2));
+ } catch (e) {
+ concurrency = 2;
}
+ return concurrency;
+ }
}
exports.BrowserCryptoWorkerFactory = BrowserCryptoWorkerFactory;
-//# sourceMappingURL=browserCryptoWorkerFactory.js.map \ No newline at end of file
+//# sourceMappingURL=browserCryptoWorkerFactory.js.map
diff --git a/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.ts b/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.ts
index a8315dc6d..ab20228ef 100644
--- a/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.ts
+++ b/packages/taler-wallet-webextension/src/browserCryptoWorkerFactory.ts
@@ -19,7 +19,10 @@
* @author Florian Dold
*/
-import type { CryptoWorker, CryptoWorkerFactory } from "@gnu-taler/taler-wallet-core";
+import type {
+ CryptoWorker,
+ CryptoWorkerFactory,
+} from "@gnu-taler/taler-wallet-core";
export class BrowserCryptoWorkerFactory implements CryptoWorkerFactory {
startWorker(): CryptoWorker {
diff --git a/packages/taler-wallet-webextension/src/compat.js b/packages/taler-wallet-webextension/src/compat.js
index fdfcbd4b9..48e49a0a7 100644
--- a/packages/taler-wallet-webextension/src/compat.js
+++ b/packages/taler-wallet-webextension/src/compat.js
@@ -21,41 +21,44 @@ exports.getPermissionsApi = exports.isNode = exports.isFirefox = void 0;
* WebExtension APIs consistently.
*/
function isFirefox() {
- const rt = chrome.runtime;
- if (typeof rt.getBrowserInfo === "function") {
- return true;
- }
- return false;
+ const rt = chrome.runtime;
+ if (typeof rt.getBrowserInfo === "function") {
+ return true;
+ }
+ return false;
}
exports.isFirefox = isFirefox;
/**
* Check if we are running under nodejs.
*/
function isNode() {
- return typeof process !== "undefined" && process.release.name === "node";
+ return typeof process !== "undefined" && process.release.name === "node";
}
exports.isNode = isNode;
function getPermissionsApi() {
- const myBrowser = globalThis.browser;
- if (typeof myBrowser === "object" &&
- typeof myBrowser.permissions === "object") {
- return {
- addPermissionsListener: () => {
- // Not supported yet.
- },
- contains: myBrowser.permissions.contains,
- request: myBrowser.permissions.request,
- remove: myBrowser.permissions.remove,
- };
- }
- else {
- return {
- addPermissionsListener: chrome.permissions.onAdded.addListener.bind(chrome.permissions.onAdded),
- contains: chrome.permissions.contains,
- request: chrome.permissions.request,
- remove: chrome.permissions.remove,
- };
- }
+ const myBrowser = globalThis.browser;
+ if (
+ typeof myBrowser === "object" &&
+ typeof myBrowser.permissions === "object"
+ ) {
+ return {
+ addPermissionsListener: () => {
+ // Not supported yet.
+ },
+ contains: myBrowser.permissions.contains,
+ request: myBrowser.permissions.request,
+ remove: myBrowser.permissions.remove,
+ };
+ } else {
+ return {
+ addPermissionsListener: chrome.permissions.onAdded.addListener.bind(
+ chrome.permissions.onAdded,
+ ),
+ contains: chrome.permissions.contains,
+ request: chrome.permissions.request,
+ remove: chrome.permissions.remove,
+ };
+ }
}
exports.getPermissionsApi = getPermissionsApi;
-//# sourceMappingURL=compat.js.map \ No newline at end of file
+//# sourceMappingURL=compat.js.map
diff --git a/packages/taler-wallet-webextension/src/components/Checkbox.tsx b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
index 2d7b98087..276ac9ff0 100644
--- a/packages/taler-wallet-webextension/src/components/Checkbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/Checkbox.tsx
@@ -24,7 +24,13 @@ interface Props {
name: string;
description?: string;
}
-export function Checkbox({ name, enabled, onToggle, label, description }: Props): JSX.Element {
+export function Checkbox({
+ name,
+ enabled,
+ onToggle,
+ label,
+ description,
+}: Props): JSX.Element {
return (
<div>
<input
@@ -32,23 +38,26 @@ export function Checkbox({ name, enabled, onToggle, label, description }: Props)
onClick={onToggle}
type="checkbox"
id={`checkbox-${name}`}
- style={{ width: "1.5em", height: "1.5em", verticalAlign: "middle" }} />
+ style={{ width: "1.5em", height: "1.5em", verticalAlign: "middle" }}
+ />
<label
htmlFor={`checkbox-${name}`}
style={{ marginLeft: "0.5em", fontWeight: "bold" }}
>
{label}
</label>
- {description && <span
- style={{
- color: "#383838",
- fontSize: "smaller",
- display: "block",
- marginLeft: "2em",
- }}
- >
- {description}
- </span>}
+ {description && (
+ <span
+ style={{
+ color: "#383838",
+ fontSize: "smaller",
+ display: "block",
+ marginLeft: "2em",
+ }}
+ >
+ {description}
+ </span>
+ )}
</div>
);
}
diff --git a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
index 5e30ee3d1..2fc8316f5 100644
--- a/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
+++ b/packages/taler-wallet-webextension/src/components/CheckboxOutlined.tsx
@@ -16,7 +16,7 @@
import { JSX } from "preact/jsx-runtime";
import { Outlined, StyledCheckboxLabel } from "./styled/index";
-import { h } from 'preact';
+import { h } from "preact";
interface Props {
enabled: boolean;
@@ -25,28 +25,39 @@ interface Props {
name: string;
}
+const Tick = () => (
+ <svg
+ xmlns="http://www.w3.org/2000/svg"
+ viewBox="0 0 24 24"
+ aria-hidden="true"
+ focusable="false"
+ style={{ backgroundColor: "green" }}
+ >
+ <path
+ fill="none"
+ stroke="white"
+ stroke-width="3"
+ d="M1.73 12.91l6.37 6.37L22.79 4.59"
+ />
+ </svg>
+);
-const Tick = () => <svg
- xmlns="http://www.w3.org/2000/svg"
- viewBox="0 0 24 24"
- aria-hidden="true"
- focusable="false"
- style={{ backgroundColor: 'green' }}
->
- <path
- fill="none"
- stroke="white"
- stroke-width="3"
- d="M1.73 12.91l6.37 6.37L22.79 4.59"
- />
-</svg>
-
-export function CheckboxOutlined({ name, enabled, onToggle, label }: Props): JSX.Element {
+export function CheckboxOutlined({
+ name,
+ enabled,
+ onToggle,
+ label,
+}: Props): JSX.Element {
return (
<Outlined>
<StyledCheckboxLabel onClick={onToggle}>
<span>
- <input type="checkbox" name={name} checked={enabled} disabled={false} />
+ <input
+ type="checkbox"
+ name={name}
+ checked={enabled}
+ disabled={false}
+ />
<div>
<Tick />
</div>
diff --git a/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
index f0c682ccb..952df15ae 100644
--- a/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
+++ b/packages/taler-wallet-webextension/src/components/DebugCheckbox.tsx
@@ -14,9 +14,15 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
- import { JSX, h } from "preact";
+import { JSX, h } from "preact";
-export function DebugCheckbox({ enabled, onToggle }: { enabled: boolean; onToggle: () => void; }): JSX.Element {
+export function DebugCheckbox({
+ enabled,
+ onToggle,
+}: {
+ enabled: boolean;
+ onToggle: () => void;
+}): JSX.Element {
return (
<div>
<input
@@ -24,7 +30,8 @@ export function DebugCheckbox({ enabled, onToggle }: { enabled: boolean; onToggl
onClick={onToggle}
type="checkbox"
id="checkbox-perm"
- style={{ width: "1.5em", height: "1.5em", verticalAlign: "middle" }} />
+ style={{ width: "1.5em", height: "1.5em", verticalAlign: "middle" }}
+ />
<label
htmlFor="checkbox-perm"
style={{ marginLeft: "0.5em", fontWeight: "bold" }}
diff --git a/packages/taler-wallet-webextension/src/components/Diagnostics.tsx b/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
index b48deb847..0f8afd525 100644
--- a/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
+++ b/packages/taler-wallet-webextension/src/components/Diagnostics.tsx
@@ -21,11 +21,13 @@ import { PageLink } from "../renderHtml";
interface Props {
timedOut: boolean;
- diagnostics: WalletDiagnostics | undefined
+ diagnostics: WalletDiagnostics | undefined;
}
-export function Diagnostics({timedOut, diagnostics}: Props): JSX.Element | null {
-
+export function Diagnostics({
+ timedOut,
+ diagnostics,
+}: Props): JSX.Element | null {
if (timedOut) {
return <p>Diagnostics timed out. Could not talk to the wallet backend.</p>;
}
@@ -60,8 +62,8 @@ export function Diagnostics({timedOut, diagnostics}: Props): JSX.Element | null
<p>
Your wallet database is outdated. Currently automatic migration is
not supported. Please go{" "}
- <PageLink pageName="/reset-required">here</PageLink> to reset
- the wallet database.
+ <PageLink pageName="/reset-required">here</PageLink> to reset the
+ wallet database.
</p>
) : null}
</div>
diff --git a/packages/taler-wallet-webextension/src/components/EditableText.tsx b/packages/taler-wallet-webextension/src/components/EditableText.tsx
index 6f3388bf9..8b3e6d375 100644
--- a/packages/taler-wallet-webextension/src/components/EditableText.tsx
+++ b/packages/taler-wallet-webextension/src/components/EditableText.tsx
@@ -25,25 +25,37 @@ interface Props {
name: string;
description?: string;
}
-export function EditableText({ name, value, onChange, label, description }: Props): JSX.Element {
- const [editing, setEditing] = useState(false)
- const ref = useRef<HTMLInputElement>(null)
+export function EditableText({
+ name,
+ value,
+ onChange,
+ label,
+ description,
+}: Props): JSX.Element {
+ const [editing, setEditing] = useState(false);
+ const ref = useRef<HTMLInputElement>(null);
let InputText;
if (!editing) {
- InputText = () => <div style={{ display: 'flex', justifyContent: 'space-between' }}>
- <p>{value}</p>
- <button onClick={() => setEditing(true)}>edit</button>
- </div>
+ InputText = () => (
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <p>{value}</p>
+ <button onClick={() => setEditing(true)}>edit</button>
+ </div>
+ );
} else {
- InputText = () => <div style={{ display: 'flex', justifyContent: 'space-between' }}>
- <input
- value={value}
- ref={ref}
- type="text"
- id={`text-${name}`}
- />
- <button onClick={() => { if (ref.current) onChange(ref.current.value).then(r => setEditing(false)) }}>confirm</button>
- </div>
+ InputText = () => (
+ <div style={{ display: "flex", justifyContent: "space-between" }}>
+ <input value={value} ref={ref} type="text" id={`text-${name}`} />
+ <button
+ onClick={() => {
+ if (ref.current)
+ onChange(ref.current.value).then((r) => setEditing(false));
+ }}
+ >
+ confirm
+ </button>
+ </div>
+ );
}
return (
<div>
@@ -54,16 +66,18 @@ export function EditableText({ name, value, onChange, label, description }: Prop
{label}
</label>
<InputText />
- {description && <span
- style={{
- color: "#383838",
- fontSize: "smaller",
- display: "block",
- marginLeft: "2em",
- }}
- >
- {description}
- </span>}
+ {description && (
+ <span
+ style={{
+ color: "#383838",
+ fontSize: "smaller",
+ display: "block",
+ marginLeft: "2em",
+ }}
+ >
+ {description}
+ </span>
+ )}
</div>
);
}
diff --git a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
index cfcef16d5..c6b64fb6a 100644
--- a/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
+++ b/packages/taler-wallet-webextension/src/components/ErrorMessage.tsx
@@ -13,22 +13,35 @@
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/>
*/
- import { VNode, h } from "preact";
+import { VNode, h } from "preact";
import { useState } from "preact/hooks";
-import arrowDown from '../../static/img/chevron-down.svg';
+import arrowDown from "../../static/img/chevron-down.svg";
import { ErrorBox } from "./styled";
-export function ErrorMessage({ title, description }: { title?: string|VNode; description?: string; }) {
+export function ErrorMessage({
+ title,
+ description,
+}: {
+ title?: string | VNode;
+ description?: string;
+}) {
const [showErrorDetail, setShowErrorDetail] = useState(false);
- if (!title)
- return null;
- return <ErrorBox style={{paddingTop: 0, paddingBottom: 0}}>
- <div>
- <p>{title}</p>
- { description && <button onClick={() => { setShowErrorDetail(v => !v); }}>
- <img style={{ height: '1.5em' }} src={arrowDown} />
- </button> }
- </div>
- {showErrorDetail && <p>{description}</p>}
- </ErrorBox>;
+ if (!title) return null;
+ return (
+ <ErrorBox style={{ paddingTop: 0, paddingBottom: 0 }}>
+ <div>
+ <p>{title}</p>
+ {description && (
+ <button
+ onClick={() => {
+ setShowErrorDetail((v) => !v);
+ }}
+ >
+ <img style={{ height: "1.5em" }} src={arrowDown} />
+ </button>
+ )}
+ </div>
+ {showErrorDetail && <p>{description}</p>}
+ </ErrorBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx b/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
index cfa20280f..6d2731cd8 100644
--- a/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
+++ b/packages/taler-wallet-webextension/src/components/ExchangeToS.tsx
@@ -13,66 +13,80 @@
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/>
*/
- import { Fragment, VNode } from "preact"
-import { useState } from "preact/hooks"
-import { JSXInternal } from "preact/src/jsx"
-import { h } from 'preact';
+import { Fragment, VNode } from "preact";
+import { useState } from "preact/hooks";
+import { JSXInternal } from "preact/src/jsx";
+import { h } from "preact";
export function ExchangeXmlTos({ doc }: { doc: Document }) {
- const termsNode = doc.querySelector('[ids=terms-of-service]')
+ const termsNode = doc.querySelector("[ids=terms-of-service]");
if (!termsNode) {
- return <div>
- <p>The exchange send us an xml but there is no node with 'ids=terms-of-service'. This is the content:</p>
- <pre>{new XMLSerializer().serializeToString(doc)}</pre>
- </div>
+ return (
+ <div>
+ <p>
+ The exchange send us an xml but there is no node with
+ 'ids=terms-of-service'. This is the content:
+ </p>
+ <pre>{new XMLSerializer().serializeToString(doc)}</pre>
+ </div>
+ );
}
- return <Fragment>
- {Array.from(termsNode.children).map(renderChild)}
- </Fragment>
+ return <Fragment>{Array.from(termsNode.children).map(renderChild)}</Fragment>;
}
/**
* Map XML elements into HTML
- * @param child
- * @returns
+ * @param child
+ * @returns
*/
function renderChild(child: Element): VNode {
- const children = Array.from(child.children)
+ const children = Array.from(child.children);
switch (child.nodeName) {
- case 'title': return <header>{child.textContent}</header>
- case '#text': return <Fragment />
- case 'paragraph': return <p>{child.textContent}</p>
- case 'section': {
- return <AnchorWithOpenState href={`#terms-${child.getAttribute('ids')}`}>
- {children.map(renderChild)}
- </AnchorWithOpenState>
+ case "title":
+ return <header>{child.textContent}</header>;
+ case "#text":
+ return <Fragment />;
+ case "paragraph":
+ return <p>{child.textContent}</p>;
+ case "section": {
+ return (
+ <AnchorWithOpenState href={`#terms-${child.getAttribute("ids")}`}>
+ {children.map(renderChild)}
+ </AnchorWithOpenState>
+ );
}
- case 'bullet_list': {
- return <ul>{children.map(renderChild)}</ul>
+ case "bullet_list": {
+ return <ul>{children.map(renderChild)}</ul>;
}
- case 'enumerated_list': {
- return <ol>{children.map(renderChild)}</ol>
+ case "enumerated_list": {
+ return <ol>{children.map(renderChild)}</ol>;
}
- case 'list_item': {
- return <li>{children.map(renderChild)}</li>
+ case "list_item": {
+ return <li>{children.map(renderChild)}</li>;
}
- case 'block_quote': {
- return <div>{children.map(renderChild)}</div>
+ case "block_quote": {
+ return <div>{children.map(renderChild)}</div>;
}
- default: return <div style={{ color: 'red', display: 'hidden' }}>unknown tag {child.nodeName} <a></a></div>
+ default:
+ return (
+ <div style={{ color: "red", display: "hidden" }}>
+ unknown tag {child.nodeName} <a></a>
+ </div>
+ );
}
}
/**
* Simple anchor with a state persisted into 'data-open' prop
- * @returns
+ * @returns
*/
-function AnchorWithOpenState(props: JSXInternal.HTMLAttributes<HTMLAnchorElement>) {
- const [open, setOpen] = useState<boolean>(false)
+function AnchorWithOpenState(
+ props: JSXInternal.HTMLAttributes<HTMLAnchorElement>,
+) {
+ const [open, setOpen] = useState<boolean>(false);
function doClick(e: JSXInternal.TargetedMouseEvent<HTMLAnchorElement>) {
setOpen(!open);
e.preventDefault();
}
- return <a data-open={open ? 'true' : 'false'} onClick={doClick} {...props} />
+ return <a data-open={open ? "true" : "false"} onClick={doClick} {...props} />;
}
-
diff --git a/packages/taler-wallet-webextension/src/components/LogoHeader.tsx b/packages/taler-wallet-webextension/src/components/LogoHeader.tsx
index 9b75c62a1..6c47dc92a 100644
--- a/packages/taler-wallet-webextension/src/components/LogoHeader.tsx
+++ b/packages/taler-wallet-webextension/src/components/LogoHeader.tsx
@@ -17,15 +17,22 @@
import { h } from "preact";
export function LogoHeader() {
- return <div style={{
- display: 'flex',
- justifyContent: 'space-around',
- margin: '2em',
- }}>
- <img style={{
- width: 150,
- height: 70,
- }} src="/static/img/logo-2021.svg" width="150" />
- </div>
-
-} \ No newline at end of file
+ return (
+ <div
+ style={{
+ display: "flex",
+ justifyContent: "space-around",
+ margin: "2em",
+ }}
+ >
+ <img
+ style={{
+ width: 150,
+ height: 70,
+ }}
+ src="/static/img/logo-2021.svg"
+ width="150"
+ />
+ </div>
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/Part.tsx b/packages/taler-wallet-webextension/src/components/Part.tsx
index 75c9df16f..c8ecb46d2 100644
--- a/packages/taler-wallet-webextension/src/components/Part.tsx
+++ b/packages/taler-wallet-webextension/src/components/Part.tsx
@@ -15,18 +15,28 @@
*/
import { AmountLike } from "@gnu-taler/taler-util";
import { ExtraLargeText, LargeText, SmallLightText } from "./styled";
-import { h } from 'preact';
+import { h } from "preact";
-export type Kind = 'positive' | 'negative' | 'neutral';
+export type Kind = "positive" | "negative" | "neutral";
interface Props {
- title: string, text: AmountLike, kind: Kind, big?: boolean
+ title: string;
+ text: AmountLike;
+ kind: Kind;
+ big?: boolean;
}
export function Part({ text, title, kind, big }: Props) {
const Text = big ? ExtraLargeText : LargeText;
- return <div style={{ margin: '1em' }}>
- <SmallLightText style={{ margin: '.5em' }}>{title}</SmallLightText>
- <Text style={{ color: kind == 'positive' ? 'green' : (kind == 'negative' ? 'red' : 'black') }}>
- {text}
- </Text>
- </div>
+ return (
+ <div style={{ margin: "1em" }}>
+ <SmallLightText style={{ margin: ".5em" }}>{title}</SmallLightText>
+ <Text
+ style={{
+ color:
+ kind == "positive" ? "green" : kind == "negative" ? "red" : "black",
+ }}
+ >
+ {text}
+ </Text>
+ </div>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/components/QR.tsx b/packages/taler-wallet-webextension/src/components/QR.tsx
index 8e3f69295..4ff1af961 100644
--- a/packages/taler-wallet-webextension/src/components/QR.tsx
+++ b/packages/taler-wallet-webextension/src/components/QR.tsx
@@ -14,24 +14,35 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
- import { h, VNode } from "preact";
- import { useEffect, useRef } from "preact/hooks";
- import qrcode from "qrcode-generator";
-
- export function QR({ text }: { text: string; }):VNode {
- const divRef = useRef<HTMLDivElement>(null);
- useEffect(() => {
- if (!divRef.current) return
- const qr = qrcode(0, 'L');
- qr.addData(text);
- qr.make();
- divRef.current.innerHTML = qr.createSvgTag({
- scalable: true,
- });
- });
-
- return <div style={{ width: '100%', display: 'flex', flexDirection: 'column', alignItems: 'center' }}>
- <div style={{ width: '50%', minWidth: 200, maxWidth: 300 }} ref={divRef} />
- </div>;
- }
- \ No newline at end of file
+import { h, VNode } from "preact";
+import { useEffect, useRef } from "preact/hooks";
+import qrcode from "qrcode-generator";
+
+export function QR({ text }: { text: string }): VNode {
+ const divRef = useRef<HTMLDivElement>(null);
+ useEffect(() => {
+ if (!divRef.current) return;
+ const qr = qrcode(0, "L");
+ qr.addData(text);
+ qr.make();
+ divRef.current.innerHTML = qr.createSvgTag({
+ scalable: true,
+ });
+ });
+
+ return (
+ <div
+ style={{
+ width: "100%",
+ display: "flex",
+ flexDirection: "column",
+ alignItems: "center",
+ }}
+ >
+ <div
+ style={{ width: "50%", minWidth: 200, maxWidth: 300 }}
+ ref={divRef}
+ />
+ </div>
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/components/SelectList.tsx b/packages/taler-wallet-webextension/src/components/SelectList.tsx
index 536e5b89a..f89ba19b2 100644
--- a/packages/taler-wallet-webextension/src/components/SelectList.tsx
+++ b/packages/taler-wallet-webextension/src/components/SelectList.tsx
@@ -23,46 +23,67 @@ interface Props {
onChange: (s: string) => void;
label: string;
list: {
- [label: string]: string
- }
+ [label: string]: string;
+ };
name: string;
description?: string;
canBeNull?: boolean;
}
-export function SelectList({ name, value, list, canBeNull, onChange, label, description }: Props): JSX.Element {
- return <div>
- <label
- htmlFor={`text-${name}`}
- style={{ marginLeft: "0.5em", fontWeight: "bold" }}
- > {label}</label>
- <NiceSelect>
- <select name={name} onChange={(e) => {
- console.log(e.currentTarget.value, value)
- onChange(e.currentTarget.value)
- }}>
- {value !== undefined ? <option selected>
- {list[value]}
- </option> : <option selected disabled>
- Select one option
- </option>}
- {Object.keys(list)
- .filter((l) => l !== value)
- .map(key => <option value={key} key={key}>{list[key]}</option>)
- }
- </select>
- </NiceSelect>
- {description && <span
- style={{
- color: "#383838",
- fontSize: "smaller",
- display: "block",
- marginLeft: "2em",
- }}
- >
- {description}
- </span>}
-
- </div>
-
+export function SelectList({
+ name,
+ value,
+ list,
+ canBeNull,
+ onChange,
+ label,
+ description,
+}: Props): JSX.Element {
+ return (
+ <div>
+ <label
+ htmlFor={`text-${name}`}
+ style={{ marginLeft: "0.5em", fontWeight: "bold" }}
+ >
+ {" "}
+ {label}
+ </label>
+ <NiceSelect>
+ <select
+ name={name}
+ onChange={(e) => {
+ console.log(e.currentTarget.value, value);
+ onChange(e.currentTarget.value);
+ }}
+ >
+ {value !== undefined ? (
+ <option selected>{list[value]}</option>
+ ) : (
+ <option selected disabled>
+ Select one option
+ </option>
+ )}
+ {Object.keys(list)
+ .filter((l) => l !== value)
+ .map((key) => (
+ <option value={key} key={key}>
+ {list[key]}
+ </option>
+ ))}
+ </select>
+ </NiceSelect>
+ {description && (
+ <span
+ style={{
+ color: "#383838",
+ fontSize: "smaller",
+ display: "block",
+ marginLeft: "2em",
+ }}
+ >
+ {description}
+ </span>
+ )}
+ </div>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
index 991e97c94..1917d5627 100644
--- a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
+++ b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx
@@ -14,18 +14,33 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountString, Timestamp, Transaction, TransactionType } from '@gnu-taler/taler-util';
-import { format, formatDistance } from 'date-fns';
-import { h } from 'preact';
-import imageBank from '../../static/img/ri-bank-line.svg';
-import imageHandHeart from '../../static/img/ri-hand-heart-line.svg';
-import imageRefresh from '../../static/img/ri-refresh-line.svg';
-import imageRefund from '../../static/img/ri-refund-2-line.svg';
-import imageShoppingCart from '../../static/img/ri-shopping-cart-line.svg';
+import {
+ AmountString,
+ Timestamp,
+ Transaction,
+ TransactionType,
+} from "@gnu-taler/taler-util";
+import { format, formatDistance } from "date-fns";
+import { h } from "preact";
+import imageBank from "../../static/img/ri-bank-line.svg";
+import imageHandHeart from "../../static/img/ri-hand-heart-line.svg";
+import imageRefresh from "../../static/img/ri-refresh-line.svg";
+import imageRefund from "../../static/img/ri-refund-2-line.svg";
+import imageShoppingCart from "../../static/img/ri-shopping-cart-line.svg";
import { Pages } from "../NavigationBar";
-import { Column, ExtraLargeText, HistoryRow, SmallLightText, LargeText, LightText } from './styled/index';
+import {
+ Column,
+ ExtraLargeText,
+ HistoryRow,
+ SmallLightText,
+ LargeText,
+ LightText,
+} from "./styled/index";
-export function TransactionItem(props: { tx: Transaction, multiCurrency: boolean }): JSX.Element {
+export function TransactionItem(props: {
+ tx: Transaction;
+ multiCurrency: boolean;
+}): JSX.Element {
const tx = props.tx;
switch (tx.type) {
case TransactionType.Withdrawal:
@@ -112,20 +127,26 @@ export function TransactionItem(props: { tx: Transaction, multiCurrency: boolean
function TransactionLayout(props: TransactionLayoutProps): JSX.Element {
const date = new Date(props.timestamp.t_ms);
- const dateStr = format(date, 'dd MMM, hh:mm')
+ const dateStr = format(date, "dd MMM, hh:mm");
return (
- <HistoryRow href={Pages.transaction.replace(':tid', props.id)}>
+ <HistoryRow href={Pages.transaction.replace(":tid", props.id)}>
<img src={props.iconPath} />
<Column>
<LargeText>
<div>{props.title}</div>
- {props.subtitle && <div style={{color:'gray', fontSize:'medium', marginTop: 5}}>{props.subtitle}</div>}
+ {props.subtitle && (
+ <div style={{ color: "gray", fontSize: "medium", marginTop: 5 }}>
+ {props.subtitle}
+ </div>
+ )}
</LargeText>
- {props.pending &&
- <LightText style={{ marginTop: 5, marginBottom: 5 }}>Waiting for confirmation</LightText>
- }
- <SmallLightText style={{marginTop:5 }}>{dateStr}</SmallLightText>
+ {props.pending && (
+ <LightText style={{ marginTop: 5, marginBottom: 5 }}>
+ Waiting for confirmation
+ </LightText>
+ )}
+ <SmallLightText style={{ marginTop: 5 }}>{dateStr}</SmallLightText>
</Column>
<TransactionAmount
pending={props.pending}
@@ -170,14 +191,18 @@ function TransactionAmount(props: TransactionAmountProps): JSX.Element {
sign = "";
}
return (
- <Column style={{
- textAlign: 'center',
- color:
- props.pending ? "gray" :
- (sign === '+' ? 'darkgreen' :
- (sign === '-' ? 'darkred' :
- undefined))
- }}>
+ <Column
+ style={{
+ textAlign: "center",
+ color: props.pending
+ ? "gray"
+ : sign === "+"
+ ? "darkgreen"
+ : sign === "-"
+ ? "darkred"
+ : undefined,
+ }}
+ >
<ExtraLargeText>
{sign}
{amount}
@@ -187,4 +212,3 @@ function TransactionAmount(props: TransactionAmountProps): JSX.Element {
</Column>
);
}
-
diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx
index 65c1f49e9..8b36dbd31 100644
--- a/packages/taler-wallet-webextension/src/components/styled/index.tsx
+++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx
@@ -14,18 +14,17 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
// need to import linaria types, otherwise compiler will complain
-import type * as Linaria from '@linaria/core';
+import type * as Linaria from "@linaria/core";
-import { styled } from '@linaria/react';
+import { styled } from "@linaria/react";
export const PaymentStatus = styled.div<{ color: string }>`
padding: 5px;
border-radius: 5px;
color: white;
- background-color: ${p => p.color};
-`
+ background-color: ${(p) => p.color};
+`;
export const WalletAction = styled.div`
display: flex;
@@ -36,9 +35,9 @@ export const WalletAction = styled.div`
margin: auto;
height: 100%;
-
+
& h1:first-child {
- margin-top: 0;
+ margin-top: 0;
}
section {
margin-bottom: 2em;
@@ -47,7 +46,7 @@ export const WalletAction = styled.div`
margin-left: 8px;
}
}
-`
+`;
export const WalletActionOld = styled.section`
border: solid 5px black;
border-radius: 10px;
@@ -59,17 +58,17 @@ export const WalletActionOld = styled.section`
margin: auto;
height: 100%;
-
+
& h1:first-child {
- margin-top: 0;
+ margin-top: 0;
}
-`
+`;
export const DateSeparator = styled.div`
color: gray;
- margin: .2em;
+ margin: 0.2em;
margin-top: 1em;
-`
+`;
export const WalletBox = styled.div<{ noPadding?: boolean }>`
display: flex;
flex-direction: column;
@@ -79,10 +78,10 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
width: 400px;
}
& > section {
- padding-left: ${({ noPadding }) => noPadding ? '0px' : '8px'};
- padding-right: ${({ noPadding }) => noPadding ? '0px' : '8px'};
+ padding-left: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
+ padding-right: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
// this margin will send the section up when used with a header
- margin-bottom: auto;
+ margin-bottom: auto;
overflow: auto;
table td {
@@ -128,13 +127,13 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>`
margin-left: 8px;
}
}
-`
+`;
export const Middle = styled.div`
- justify-content: space-around;
- display: flex;
- flex-direction: column;
- height: 100%;
-`
+ justify-content: space-around;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+`;
export const PopupBox = styled.div<{ noPadding?: boolean }>`
height: 290px;
@@ -144,9 +143,9 @@ export const PopupBox = styled.div<{ noPadding?: boolean }>`
justify-content: space-between;
& > section {
- padding: ${({ noPadding }) => noPadding ? '0px' : '8px'};
+ padding: ${({ noPadding }) => (noPadding ? "0px" : "8px")};
// this margin will send the section up when used with a header
- margin-bottom: auto;
+ margin-bottom: auto;
overflow-y: auto;
table td {
@@ -201,8 +200,7 @@ export const PopupBox = styled.div<{ noPadding?: boolean }>`
margin-left: 8px;
}
}
-
-`
+`;
export const Button = styled.button<{ upperCased?: boolean }>`
display: inline-block;
@@ -214,7 +212,7 @@ export const Button = styled.button<{ upperCased?: boolean }>`
cursor: pointer;
user-select: none;
box-sizing: border-box;
- text-transform: ${({ upperCased }) => upperCased ? 'uppercase' : 'none'};
+ text-transform: ${({ upperCased }) => (upperCased ? "uppercase" : "none")};
font-family: inherit;
font-size: 100%;
@@ -223,7 +221,7 @@ export const Button = styled.button<{ upperCased?: boolean }>`
color: rgba(0, 0, 0, 0.8); /* rgba supported */
border: 1px solid #999; /*IE 6/7/8*/
border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
- background-color: '#e6e6e6';
+ background-color: "#e6e6e6";
text-decoration: none;
border-radius: 2px;
@@ -263,7 +261,7 @@ export const Link = styled.a<{ upperCased?: boolean }>`
cursor: pointer;
user-select: none;
box-sizing: border-box;
- text-transform: ${({ upperCased }) => upperCased ? 'uppercase' : 'none'};
+ text-transform: ${({ upperCased }) => (upperCased ? "uppercase" : "none")};
font-family: inherit;
font-size: 100%;
@@ -304,9 +302,9 @@ export const FontIcon = styled.div`
text-align: center;
font-weight: bold;
/* vertical-align: text-top; */
-`
+`;
export const ButtonBox = styled(Button)`
- padding: .5em;
+ padding: 0.5em;
width: fit-content;
height: 2em;
@@ -322,89 +320,87 @@ export const ButtonBox = styled(Button)`
border-radius: 4px;
border-color: black;
color: black;
-`
-
+`;
const ButtonVariant = styled(Button)`
color: white;
border-radius: 4px;
text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
-`
+`;
export const ButtonPrimary = styled(ButtonVariant)`
background-color: rgb(66, 184, 221);
-`
+`;
export const ButtonBoxPrimary = styled(ButtonBox)`
color: rgb(66, 184, 221);
border-color: rgb(66, 184, 221);
-`
+`;
export const ButtonSuccess = styled(ButtonVariant)`
background-color: #388e3c;
-`
+`;
export const LinkSuccess = styled(Link)`
color: #388e3c;
-`
+`;
export const ButtonBoxSuccess = styled(ButtonBox)`
color: #388e3c;
border-color: #388e3c;
-`
+`;
export const ButtonWarning = styled(ButtonVariant)`
background-color: rgb(223, 117, 20);
-`
+`;
export const LinkWarning = styled(Link)`
color: rgb(223, 117, 20);
-`
+`;
export const ButtonBoxWarning = styled(ButtonBox)`
color: rgb(223, 117, 20);
border-color: rgb(223, 117, 20);
-`
+`;
export const ButtonDestructive = styled(ButtonVariant)`
background-color: rgb(202, 60, 60);
-`
+`;
export const ButtonBoxDestructive = styled(ButtonBox)`
color: rgb(202, 60, 60);
border-color: rgb(202, 60, 60);
-`
-
+`;
export const BoldLight = styled.div`
-color: gray;
-font-weight: bold;
-`
+ color: gray;
+ font-weight: bold;
+`;
export const Centered = styled.div`
text-align: center;
& > :not(:first-child) {
margin-top: 15px;
}
-`
+`;
export const Row = styled.div`
display: flex;
margin: 0.5em 0;
justify-content: space-between;
padding: 0.5em;
-`
+`;
export const Row2 = styled.div`
display: flex;
/* margin: 0.5em 0; */
justify-content: space-between;
padding: 0.5em;
-`
+`;
export const Column = styled.div`
display: flex;
flex-direction: column;
margin: 0em 1em;
justify-content: space-between;
-`
+`;
export const RowBorderGray = styled(Row)`
border: 1px solid gray;
/* border-radius: 0.5em; */
-`
+`;
export const RowLightBorderGray = styled(Row2)`
border: 1px solid lightgray;
@@ -414,7 +410,7 @@ export const RowLightBorderGray = styled(Row2)`
border: 1px solid lightgray;
background-color: red;
}
-`
+`;
export const HistoryRow = styled.a`
text-decoration: none;
@@ -423,7 +419,7 @@ export const HistoryRow = styled.a`
display: flex;
justify-content: space-between;
padding: 0.5em;
-
+
border: 1px solid lightgray;
border-top: 0px;
@@ -439,7 +435,7 @@ export const HistoryRow = styled.a`
margin-left: auto;
align-self: center;
}
-`
+`;
export const ListOfProducts = styled.div`
& > div > a > img {
@@ -453,62 +449,62 @@ export const ListOfProducts = styled.div`
margin-right: auto;
margin-left: 1em;
}
-`
+`;
export const LightText = styled.div`
color: gray;
-`
+`;
export const WarningText = styled.div`
color: rgb(223, 117, 20);
-`
+`;
export const SmallText = styled.div`
- font-size: small;
-`
+ font-size: small;
+`;
export const LargeText = styled.div`
- font-size: large;
-`
+ font-size: large;
+`;
export const ExtraLargeText = styled.div`
- font-size: x-large;
-`
+ font-size: x-large;
+`;
export const SmallLightText = styled(SmallText)`
color: gray;
-`
+`;
export const CenteredText = styled.div`
white-space: nowrap;
text-align: center;
-`
+`;
export const CenteredBoldText = styled(CenteredText)`
white-space: nowrap;
text-align: center;
font-weight: bold;
color: ${((props: any): any => String(props.color) as any) as any};
-`
+`;
export const Input = styled.div<{ invalid?: boolean }>`
& label {
display: block;
padding: 5px;
- color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
+ color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
}
& input {
display: block;
padding: 5px;
width: calc(100% - 4px - 10px);
- border-color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
+ border-color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
}
-`
+`;
export const InputWithLabel = styled.div<{ invalid?: boolean }>`
& label {
display: block;
padding: 5px;
- color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
+ color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
}
& > div {
position: relative;
@@ -516,20 +512,20 @@ export const InputWithLabel = styled.div<{ invalid?: boolean }>`
top: 0px;
bottom: 0px;
- & > div {
+ & > div {
position: absolute;
background-color: lightgray;
padding: 5px;
margin: 2px;
}
- & > input {
+ & > input {
flex: 1;
- padding: 5px;
- border-color: ${({ invalid }) => !invalid ? 'inherit' : 'red'}
+ padding: 5px;
+ border-color: ${({ invalid }) => (!invalid ? "inherit" : "red")};
}
}
-`
+`;
export const ErrorBox = styled.div`
border: 2px solid #f5c6cb;
@@ -555,22 +551,22 @@ export const ErrorBox = styled.div`
width: 28px;
}
}
-`
+`;
export const SuccessBox = styled(ErrorBox)`
color: #0f5132;
background-color: #d1e7dd;
border-color: #badbcc;
-`
+`;
export const WarningBox = styled(ErrorBox)`
color: #664d03;
background-color: #fff3cd;
border-color: #ffecb5;
-`
+`;
export const PopupNavigation = styled.div<{ devMode?: boolean }>`
- background-color:#0042b2;
+ background-color: #0042b2;
height: 35px;
justify-content: space-around;
display: flex;
@@ -582,7 +578,7 @@ export const PopupNavigation = styled.div<{ devMode?: boolean }>`
& > div > a {
color: #f8faf7;
display: inline-block;
- width: calc(400px / ${({ devMode }) => !devMode ? 4 : 5});
+ width: calc(400px / ${({ devMode }) => (!devMode ? 4 : 5)});
text-align: center;
text-decoration: none;
vertical-align: middle;
@@ -597,7 +593,6 @@ export const PopupNavigation = styled.div<{ devMode?: boolean }>`
`;
export const NiceSelect = styled.div`
-
& > select {
-webkit-appearance: none;
-moz-appearance: none;
@@ -617,19 +612,19 @@ export const NiceSelect = styled.div`
display: flex;
/* width: 10em; */
overflow: hidden;
- border-radius: .25em;
+ border-radius: 0.25em;
&::after {
- content: '\u25BC';
+ content: "\u25BC";
position: absolute;
top: 0;
right: 0;
padding: 0.5em 1em;
cursor: pointer;
pointer-events: none;
- -webkit-transition: .25s all ease;
- -o-transition: .25s all ease;
- transition: .25s all ease;
+ -webkit-transition: 0.25s all ease;
+ -o-transition: 0.25s all ease;
+ transition: 0.25s all ease;
}
&:hover::after {
@@ -639,7 +634,7 @@ export const NiceSelect = styled.div`
&::-ms-expand {
display: none;
}
-`
+`;
export const Outlined = styled.div`
border: 2px solid #388e3c;
@@ -647,13 +642,12 @@ export const Outlined = styled.div`
width: fit-content;
border-radius: 2px;
color: #388e3c;
-`
+`;
/* { width: "1.5em", height: "1.5em", verticalAlign: "middle" } */
export const CheckboxSuccess = styled.input`
vertical-align: center;
-
-`
+`;
export const TermsSection = styled.a`
border: 1px solid black;
@@ -664,13 +658,13 @@ export const TermsSection = styled.a`
text-decoration: none;
color: inherit;
flex-direction: column;
-
+
display: flex;
&[data-open="true"] {
- display: flex;
+ display: flex;
}
&[data-open="false"] > *:not(:first-child) {
- display: none;
+ display: none;
}
header {
@@ -681,11 +675,11 @@ export const TermsSection = styled.a`
height: auto;
}
- &[data-open="true"] header:after {
- content: '\\2227';
+ &[data-open="true"] header:after {
+ content: "\\2227";
}
- &[data-open="false"] header:after {
- content: '\\2228';
+ &[data-open="false"] header:after {
+ content: "\\2228";
}
`;
@@ -712,13 +706,13 @@ export const TermsOfService = styled.div`
padding: 1em;
margin-top: 2px;
margin-bottom: 2px;
-
+
display: flex;
&[data-open="true"] {
- display: flex;
+ display: flex;
}
&[data-open="false"] > *:not(:first-child) {
- display: none;
+ display: none;
}
header {
@@ -729,22 +723,20 @@ export const TermsOfService = styled.div`
height: auto;
}
- &[data-open="true"] > header:after {
- content: '\\2227';
+ &[data-open="true"] > header:after {
+ content: "\\2227";
}
- &[data-open="false"] > header:after {
- content: '\\2228';
+ &[data-open="false"] > header:after {
+ content: "\\2228";
}
}
-
-`
+`;
export const StyledCheckboxLabel = styled.div`
color: green;
text-transform: uppercase;
/* font-weight: bold; */
text-align: center;
span {
-
input {
display: none;
opacity: 0;
@@ -758,7 +750,7 @@ export const StyledCheckboxLabel = styled.div`
margin-right: 1em;
border-radius: 2px;
border: 2px solid currentColor;
-
+
svg {
transition: transform 0.1s ease-in 25ms;
transform: scale(0);
@@ -776,12 +768,11 @@ export const StyledCheckboxLabel = styled.div`
}
input:disabled + div {
color: #959495;
- };
+ }
input:disabled + div + label {
color: #959495;
- };
+ }
input:focus + div + label {
box-shadow: 0 0 0 0.05em #fff, 0 0 0.15em 0.1em currentColor;
}
-
-` \ No newline at end of file
+`;
diff --git a/packages/taler-wallet-webextension/src/context/devContext.ts b/packages/taler-wallet-webextension/src/context/devContext.ts
index ea2ba4ceb..0344df057 100644
--- a/packages/taler-wallet-webextension/src/context/devContext.ts
+++ b/packages/taler-wallet-webextension/src/context/devContext.ts
@@ -15,13 +15,13 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createContext, h, VNode } from 'preact'
-import { useContext, useState } from 'preact/hooks'
-import { useLocalStorage } from '../hooks/useLocalStorage';
+import { createContext, h, VNode } from "preact";
+import { useContext, useState } from "preact/hooks";
+import { useLocalStorage } from "../hooks/useLocalStorage";
interface Type {
devMode: boolean;
@@ -29,14 +29,14 @@ interface Type {
}
const Context = createContext<Type>({
devMode: false,
- toggleDevMode: () => null
-})
+ toggleDevMode: () => null,
+});
export const useDevContext = (): Type => useContext(Context);
export const DevContextProvider = ({ children }: { children: any }): VNode => {
- const [value, setter] = useLocalStorage('devMode')
- const devMode = value === "true"
- const toggleDevMode = () => setter(v => !v ? "true" : undefined)
+ const [value, setter] = useLocalStorage("devMode");
+ const devMode = value === "true";
+ const toggleDevMode = () => setter((v) => (!v ? "true" : undefined));
return h(Context.Provider, { value: { devMode, toggleDevMode }, children });
-}
+};
diff --git a/packages/taler-wallet-webextension/src/context/translation.ts b/packages/taler-wallet-webextension/src/context/translation.ts
index 5f57958de..105da9dcf 100644
--- a/packages/taler-wallet-webextension/src/context/translation.ts
+++ b/packages/taler-wallet-webextension/src/context/translation.ts
@@ -15,54 +15,58 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createContext, h, VNode } from 'preact'
-import { useContext, useEffect } from 'preact/hooks'
-import { useLang } from '../hooks/useLang'
+import { createContext, h, VNode } from "preact";
+import { useContext, useEffect } from "preact/hooks";
+import { useLang } from "../hooks/useLang";
//@ts-ignore: type declaration
import * as jedLib from "jed";
import { strings } from "../i18n/strings";
-import { setupI18n } from '@gnu-taler/taler-util';
+import { setupI18n } from "@gnu-taler/taler-util";
interface Type {
lang: string;
changeLanguage: (l: string) => void;
}
const initial = {
- lang: 'en',
+ lang: "en",
changeLanguage: () => {
// do not change anything
- }
-}
-const Context = createContext<Type>(initial)
+ },
+};
+const Context = createContext<Type>(initial);
interface Props {
- initial?: string,
- children: any,
- forceLang?: string
+ initial?: string;
+ children: any;
+ forceLang?: string;
}
-//we use forceLang when we don't want to use the saved state, but sone forced
-//runtime lang predefined lang
-export const TranslationProvider = ({ initial, children, forceLang }: Props): VNode => {
- const [lang, changeLanguage] = useLang(initial)
+//we use forceLang when we don't want to use the saved state, but sone forced
+//runtime lang predefined lang
+export const TranslationProvider = ({
+ initial,
+ children,
+ forceLang,
+}: Props): VNode => {
+ const [lang, changeLanguage] = useLang(initial);
useEffect(() => {
if (forceLang) {
- changeLanguage(forceLang)
+ changeLanguage(forceLang);
}
- })
- useEffect(()=> {
- setupI18n(lang, strings)
- },[lang])
+ });
+ useEffect(() => {
+ setupI18n(lang, strings);
+ }, [lang]);
if (forceLang) {
- setupI18n(forceLang, strings)
+ setupI18n(forceLang, strings);
} else {
- setupI18n(lang, strings)
+ setupI18n(lang, strings);
}
return h(Context.Provider, { value: { lang, changeLanguage }, children });
-}
+};
export const useTranslationContext = (): Type => useContext(Context);
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
index 622e7950f..c2d360d3b 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.stories.tsx
@@ -15,150 +15,156 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ContractTerms, PreparePayResultType } from '@gnu-taler/taler-util';
-import { createExample } from '../test-utils';
-import { PaymentRequestView as TestedComponent } from './Pay';
+import { ContractTerms, PreparePayResultType } from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils";
+import { PaymentRequestView as TestedComponent } from "./Pay";
export default {
- title: 'cta/pay',
+ title: "cta/pay",
component: TestedComponent,
- argTypes: {
- },
+ argTypes: {},
};
export const NoBalance = createExample(TestedComponent, {
payStatus: {
status: PreparePayResultType.InsufficientBalance,
- noncePriv: '',
+ noncePriv: "",
proposalId: "proposal1234",
- contractTerms: {
+ contractTerms: ({
merchant: {
- name: 'someone'
+ name: "someone",
},
- summary: 'some beers',
- amount: 'USD:10',
- } as Partial<ContractTerms> as any,
- amountRaw: 'USD:10',
- }
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms>) as any,
+ amountRaw: "USD:10",
+ },
});
export const NoEnoughBalance = createExample(TestedComponent, {
payStatus: {
status: PreparePayResultType.InsufficientBalance,
- noncePriv: '',
+ noncePriv: "",
proposalId: "proposal1234",
- contractTerms: {
+ contractTerms: ({
merchant: {
- name: 'someone'
+ name: "someone",
},
- summary: 'some beers',
- amount: 'USD:10',
- } as Partial<ContractTerms> as any,
- amountRaw: 'USD:10',
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms>) as any,
+ amountRaw: "USD:10",
},
balance: {
- currency: 'USD',
+ currency: "USD",
fraction: 40000000,
- value: 9
- }
+ value: 9,
+ },
});
export const PaymentPossible = createExample(TestedComponent, {
- uri: 'taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0',
+ uri:
+ "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
status: PreparePayResultType.PaymentPossible,
- amountEffective: 'USD:10',
- amountRaw: 'USD:10',
- noncePriv: '',
- contractTerms: {
- nonce: '123213123',
+ amountEffective: "USD:10",
+ amountRaw: "USD:10",
+ noncePriv: "",
+ contractTerms: ({
+ nonce: "123213123",
merchant: {
- name: 'someone'
+ name: "someone",
},
- amount: 'USD:10',
- summary: 'some beers',
- } as Partial<ContractTerms> as any,
- contractTermsHash: '123456',
- proposalId: 'proposal1234'
- }
+ amount: "USD:10",
+ summary: "some beers",
+ } as Partial<ContractTerms>) as any,
+ contractTermsHash: "123456",
+ proposalId: "proposal1234",
+ },
});
export const PaymentPossibleWithFee = createExample(TestedComponent, {
- uri: 'taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0',
+ uri:
+ "taler://pay/merchant-backend.taler/2021.242-01G2X4275RBWG/?c=66BE594PDZR24744J6EQK52XM0",
payStatus: {
status: PreparePayResultType.PaymentPossible,
- amountEffective: 'USD:10.20',
- amountRaw: 'USD:10',
- noncePriv: '',
- contractTerms: {
- nonce: '123213123',
+ amountEffective: "USD:10.20",
+ amountRaw: "USD:10",
+ noncePriv: "",
+ contractTerms: ({
+ nonce: "123213123",
merchant: {
- name: 'someone'
+ name: "someone",
},
- amount: 'USD:10',
- summary: 'some beers',
- } as Partial<ContractTerms> as any,
- contractTermsHash: '123456',
- proposalId: 'proposal1234'
- }
+ amount: "USD:10",
+ summary: "some beers",
+ } as Partial<ContractTerms>) as any,
+ contractTermsHash: "123456",
+ proposalId: "proposal1234",
+ },
});
export const AlreadyConfirmedWithFullfilment = createExample(TestedComponent, {
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
- amountEffective: 'USD:10',
- amountRaw: 'USD:10',
- contractTerms: {
+ amountEffective: "USD:10",
+ amountRaw: "USD:10",
+ contractTerms: ({
merchant: {
- name: 'someone'
+ name: "someone",
},
- fulfillment_message: 'congratulations! you are looking at the fulfillment message! ',
- summary: 'some beers',
- amount: 'USD:10',
- } as Partial<ContractTerms> as any,
- contractTermsHash: '123456',
- proposalId: 'proposal1234',
+ fulfillment_message:
+ "congratulations! you are looking at the fulfillment message! ",
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms>) as any,
+ contractTermsHash: "123456",
+ proposalId: "proposal1234",
paid: false,
- }
+ },
});
-export const AlreadyConfirmedWithoutFullfilment = createExample(TestedComponent, {
- payStatus: {
- status: PreparePayResultType.AlreadyConfirmed,
- amountEffective: 'USD:10',
- amountRaw: 'USD:10',
- contractTerms: {
- merchant: {
- name: 'someone'
- },
- summary: 'some beers',
- amount: 'USD:10',
- } as Partial<ContractTerms> as any,
- contractTermsHash: '123456',
- proposalId: 'proposal1234',
- paid: false,
- }
-});
+export const AlreadyConfirmedWithoutFullfilment = createExample(
+ TestedComponent,
+ {
+ payStatus: {
+ status: PreparePayResultType.AlreadyConfirmed,
+ amountEffective: "USD:10",
+ amountRaw: "USD:10",
+ contractTerms: ({
+ merchant: {
+ name: "someone",
+ },
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms>) as any,
+ contractTermsHash: "123456",
+ proposalId: "proposal1234",
+ paid: false,
+ },
+ },
+);
export const AlreadyPaid = createExample(TestedComponent, {
payStatus: {
status: PreparePayResultType.AlreadyConfirmed,
- amountEffective: 'USD:10',
- amountRaw: 'USD:10',
- contractTerms: {
+ amountEffective: "USD:10",
+ amountRaw: "USD:10",
+ contractTerms: ({
merchant: {
- name: 'someone'
+ name: "someone",
},
- fulfillment_message: 'congratulations! you are looking at the fulfillment message! ',
- summary: 'some beers',
- amount: 'USD:10',
- } as Partial<ContractTerms> as any,
- contractTermsHash: '123456',
- proposalId: 'proposal1234',
+ fulfillment_message:
+ "congratulations! you are looking at the fulfillment message! ",
+ summary: "some beers",
+ amount: "USD:10",
+ } as Partial<ContractTerms>) as any,
+ contractTermsHash: "123456",
+ proposalId: "proposal1234",
paid: true,
- }
+ },
});
diff --git a/packages/taler-wallet-webextension/src/cta/Pay.tsx b/packages/taler-wallet-webextension/src/cta/Pay.tsx
index 675b14ff9..1023013d2 100644
--- a/packages/taler-wallet-webextension/src/cta/Pay.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Pay.tsx
@@ -24,18 +24,36 @@
*/
// import * as i18n from "../i18n";
-import { AmountJson, AmountLike, Amounts, ConfirmPayResult, ConfirmPayResultDone, ConfirmPayResultType, ContractTerms, getJsonI18n, i18n, PreparePayResult, PreparePayResultType } from "@gnu-taler/taler-util";
-import { Fragment, JSX, VNode } from "preact";
+import {
+ AmountJson,
+ AmountLike,
+ Amounts,
+ ConfirmPayResult,
+ ConfirmPayResultDone,
+ ConfirmPayResultType,
+ ContractTerms,
+ i18n,
+ PreparePayResult,
+ PreparePayResultType,
+} from "@gnu-taler/taler-util";
+import { h, Fragment, JSX, VNode } from "preact";
import { useEffect, useState } from "preact/hooks";
import { LogoHeader } from "../components/LogoHeader";
import { Part } from "../components/Part";
import { QR } from "../components/QR";
-import { ButtonSuccess, ErrorBox, LinkSuccess, SuccessBox, WalletAction, WarningBox } from "../components/styled";
+import {
+ ButtonSuccess,
+ ErrorBox,
+ LinkSuccess,
+ SuccessBox,
+ WalletAction,
+ WarningBox,
+} from "../components/styled";
import { useBalances } from "../hooks/useBalances";
import * as wxApi from "../wxApi";
interface Props {
- talerPayUri?: string
+ talerPayUri?: string;
}
// export function AlreadyPaid({ payStatus }: { payStatus: PreparePayResult }) {
@@ -64,7 +82,9 @@ interface Props {
// </section>
// }
-const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultDone> => {
+const doPayment = async (
+ payStatus: PreparePayResult,
+): Promise<ConfirmPayResultDone> => {
if (payStatus.status !== "payment-possible") {
throw Error(`invalid state: ${payStatus.status}`);
}
@@ -80,18 +100,29 @@ const doPayment = async (payStatus: PreparePayResult): Promise<ConfirmPayResultD
return res;
};
-
-
export function PayPage({ talerPayUri }: Props): JSX.Element {
- const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(undefined);
- const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(undefined);
+ const [payStatus, setPayStatus] = useState<PreparePayResult | undefined>(
+ undefined,
+ );
+ const [payResult, setPayResult] = useState<ConfirmPayResult | undefined>(
+ undefined,
+ );
const [payErrMsg, setPayErrMsg] = useState<string | undefined>(undefined);
- const balance = useBalances()
- const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || [])
+ const balance = useBalances();
+ const balanceWithoutError = balance?.hasError
+ ? []
+ : balance?.response.balances || [];
- const foundBalance = balanceWithoutError.find(b => payStatus && Amounts.parseOrThrow(b.available).currency === Amounts.parseOrThrow(payStatus?.amountRaw).currency)
- const foundAmount = foundBalance ? Amounts.parseOrThrow(foundBalance.available) : undefined
+ const foundBalance = balanceWithoutError.find(
+ (b) =>
+ payStatus &&
+ Amounts.parseOrThrow(b.available).currency ===
+ Amounts.parseOrThrow(payStatus?.amountRaw).currency,
+ );
+ const foundAmount = foundBalance
+ ? Amounts.parseOrThrow(foundBalance.available)
+ : undefined;
useEffect(() => {
if (!talerPayUri) return;
@@ -101,7 +132,7 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
setPayStatus(p);
} catch (e) {
if (e instanceof Error) {
- setPayErrMsg(e.message)
+ setPayErrMsg(e.message);
}
}
};
@@ -109,30 +140,28 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
}, [talerPayUri]);
if (!talerPayUri) {
- return <span>missing pay uri</span>
+ return <span>missing pay uri</span>;
}
if (!payStatus) {
if (payErrMsg) {
- return <WalletAction>
- <LogoHeader />
- <h2>
- {i18n.str`Digital cash payment`}
- </h2>
- <section>
- <p>Could not get the payment information for this order</p>
- <ErrorBox>
- {payErrMsg}
- </ErrorBox>
- </section>
- </WalletAction>
+ return (
+ <WalletAction>
+ <LogoHeader />
+ <h2>{i18n.str`Digital cash payment`}</h2>
+ <section>
+ <p>Could not get the payment information for this order</p>
+ <ErrorBox>{payErrMsg}</ErrorBox>
+ </section>
+ </WalletAction>
+ );
}
return <span>Loading payment information ...</span>;
}
const onClick = async () => {
try {
- const res = await doPayment(payStatus)
+ const res = await doPayment(payStatus);
setPayResult(res);
} catch (e) {
console.error(e);
@@ -140,13 +169,18 @@ export function PayPage({ talerPayUri }: Props): JSX.Element {
setPayErrMsg(e.message);
}
}
+ };
- }
-
- return <PaymentRequestView uri={talerPayUri}
- payStatus={payStatus} payResult={payResult}
- onClick={onClick} payErrMsg={payErrMsg}
- balance={foundAmount} />;
+ return (
+ <PaymentRequestView
+ uri={talerPayUri}
+ payStatus={payStatus}
+ payResult={payResult}
+ onClick={onClick}
+ payErrMsg={payErrMsg}
+ balance={foundAmount}
+ />
+ );
}
export interface PaymentRequestViewProps {
@@ -157,7 +191,14 @@ export interface PaymentRequestViewProps {
uri: string;
balance: AmountJson | undefined;
}
-export function PaymentRequestView({ uri, payStatus, payResult, onClick, payErrMsg, balance }: PaymentRequestViewProps) {
+export function PaymentRequestView({
+ uri,
+ payStatus,
+ payResult,
+ onClick,
+ payErrMsg,
+ balance,
+}: PaymentRequestViewProps) {
let totalFees: AmountJson = Amounts.getZero(payStatus.amountRaw);
const contractTerms: ContractTerms = payStatus.contractTerms;
@@ -185,116 +226,174 @@ export function PaymentRequestView({ uri, payStatus, payResult, onClick, payErrM
}
function Alternative() {
- const [showQR, setShowQR] = useState<boolean>(false)
- const privateUri = payStatus.status !== PreparePayResultType.AlreadyConfirmed ? `${uri}&n=${payStatus.noncePriv}` : uri
- return <section>
- <LinkSuccess upperCased onClick={() => setShowQR(qr => !qr)}>
- {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
- </LinkSuccess>
- {showQR && <div>
- <QR text={privateUri} />
- Scan the QR code or <a href={privateUri}>click here</a>
- </div>}
- </section>
+ const [showQR, setShowQR] = useState<boolean>(false);
+ const privateUri =
+ payStatus.status !== PreparePayResultType.AlreadyConfirmed
+ ? `${uri}&n=${payStatus.noncePriv}`
+ : uri;
+ return (
+ <section>
+ <LinkSuccess upperCased onClick={() => setShowQR((qr) => !qr)}>
+ {!showQR ? i18n.str`Pay with a mobile phone` : i18n.str`Hide QR`}
+ </LinkSuccess>
+ {showQR && (
+ <div>
+ <QR text={privateUri} />
+ Scan the QR code or <a href={privateUri}>click here</a>
+ </div>
+ )}
+ </section>
+ );
}
function ButtonsSection() {
if (payResult) {
if (payResult.type === ConfirmPayResultType.Pending) {
- return <section>
- <div>
- <p>Processing...</p>
- </div>
- </section>
+ return (
+ <section>
+ <div>
+ <p>Processing...</p>
+ </div>
+ </section>
+ );
}
- return null
+ return null;
}
if (payErrMsg) {
- return <section>
- <div>
- <p>Payment failed: {payErrMsg}</p>
- <button class="pure-button button-success" onClick={onClick} >
- {i18n.str`Retry`}
- </button>
- </div>
- </section>
- }
- if (payStatus.status === PreparePayResultType.PaymentPossible) {
- return <Fragment>
+ return (
<section>
- <ButtonSuccess upperCased onClick={onClick}>
- {i18n.str`Pay`} {amountToString(payStatus.amountEffective)}
- </ButtonSuccess>
+ <div>
+ <p>Payment failed: {payErrMsg}</p>
+ <button class="pure-button button-success" onClick={onClick}>
+ {i18n.str`Retry`}
+ </button>
+ </div>
</section>
- <Alternative />
- </Fragment>
+ );
+ }
+ if (payStatus.status === PreparePayResultType.PaymentPossible) {
+ return (
+ <Fragment>
+ <section>
+ <ButtonSuccess upperCased onClick={onClick}>
+ {i18n.str`Pay`} {amountToString(payStatus.amountEffective)}
+ </ButtonSuccess>
+ </section>
+ <Alternative />
+ </Fragment>
+ );
}
if (payStatus.status === PreparePayResultType.InsufficientBalance) {
- return <Fragment>
- <section>
- {balance ? <WarningBox>
- Your balance of {amountToString(balance)} is not enough to pay for this purchase
- </WarningBox> : <WarningBox>
- Your balance is not enough to pay for this purchase.
- </WarningBox>}
- </section>
- <section>
- <ButtonSuccess upperCased>
- {i18n.str`Withdraw digital cash`}
- </ButtonSuccess>
- </section>
- <Alternative />
- </Fragment>
+ return (
+ <Fragment>
+ <section>
+ {balance ? (
+ <WarningBox>
+ Your balance of {amountToString(balance)} is not enough to pay
+ for this purchase
+ </WarningBox>
+ ) : (
+ <WarningBox>
+ Your balance is not enough to pay for this purchase.
+ </WarningBox>
+ )}
+ </section>
+ <section>
+ <ButtonSuccess upperCased>
+ {i18n.str`Withdraw digital cash`}
+ </ButtonSuccess>
+ </section>
+ <Alternative />
+ </Fragment>
+ );
}
if (payStatus.status === PreparePayResultType.AlreadyConfirmed) {
- return <Fragment>
- <section>
- {payStatus.paid && contractTerms.fulfillment_message && <Part title="Merchant message" text={contractTerms.fulfillment_message} kind='neutral' />}
- </section>
- {!payStatus.paid && <Alternative />}
- </Fragment>
+ return (
+ <Fragment>
+ <section>
+ {payStatus.paid && contractTerms.fulfillment_message && (
+ <Part
+ title="Merchant message"
+ text={contractTerms.fulfillment_message}
+ kind="neutral"
+ />
+ )}
+ </section>
+ {!payStatus.paid && <Alternative />}
+ </Fragment>
+ );
}
- return <span />
+ return <span />;
}
- return <WalletAction>
- <LogoHeader />
-
- <h2>
- {i18n.str`Digital cash payment`}
- </h2>
- {payStatus.status === PreparePayResultType.AlreadyConfirmed &&
- (payStatus.paid ? <SuccessBox> Already paid </SuccessBox> : <WarningBox> Already claimed </WarningBox>)
- }
- {payResult && payResult.type === ConfirmPayResultType.Done && (
- <SuccessBox>
- <h3>Payment complete</h3>
- <p>{!payResult.contractTerms.fulfillment_message ?
- "You will now be sent back to the merchant you came from." :
- payResult.contractTerms.fulfillment_message
- }</p>
- </SuccessBox>
- )}
- <section>
- {payStatus.status !== PreparePayResultType.InsufficientBalance && Amounts.isNonZero(totalFees) &&
- <Part big title="Total to pay" text={amountToString(payStatus.amountEffective)} kind='negative' />
- }
- <Part big title="Purchase amount" text={amountToString(payStatus.amountRaw)} kind='neutral' />
- {Amounts.isNonZero(totalFees) && <Fragment>
- <Part big title="Fee" text={amountToString(totalFees)} kind='negative' />
- </Fragment>
- }
- <Part title="Merchant" text={contractTerms.merchant.name} kind='neutral' />
- <Part title="Purchase" text={contractTerms.summary} kind='neutral' />
- {contractTerms.order_id && <Part title="Receipt" text={`#${contractTerms.order_id}`} kind='neutral' />}
- </section>
- <ButtonsSection />
+ return (
+ <WalletAction>
+ <LogoHeader />
- </WalletAction>
+ <h2>{i18n.str`Digital cash payment`}</h2>
+ {payStatus.status === PreparePayResultType.AlreadyConfirmed &&
+ (payStatus.paid ? (
+ <SuccessBox> Already paid </SuccessBox>
+ ) : (
+ <WarningBox> Already claimed </WarningBox>
+ ))}
+ {payResult && payResult.type === ConfirmPayResultType.Done && (
+ <SuccessBox>
+ <h3>Payment complete</h3>
+ <p>
+ {!payResult.contractTerms.fulfillment_message
+ ? "You will now be sent back to the merchant you came from."
+ : payResult.contractTerms.fulfillment_message}
+ </p>
+ </SuccessBox>
+ )}
+ <section>
+ {payStatus.status !== PreparePayResultType.InsufficientBalance &&
+ Amounts.isNonZero(totalFees) && (
+ <Part
+ big
+ title="Total to pay"
+ text={amountToString(payStatus.amountEffective)}
+ kind="negative"
+ />
+ )}
+ <Part
+ big
+ title="Purchase amount"
+ text={amountToString(payStatus.amountRaw)}
+ kind="neutral"
+ />
+ {Amounts.isNonZero(totalFees) && (
+ <Fragment>
+ <Part
+ big
+ title="Fee"
+ text={amountToString(totalFees)}
+ kind="negative"
+ />
+ </Fragment>
+ )}
+ <Part
+ title="Merchant"
+ text={contractTerms.merchant.name}
+ kind="neutral"
+ />
+ <Part title="Purchase" text={contractTerms.summary} kind="neutral" />
+ {contractTerms.order_id && (
+ <Part
+ title="Receipt"
+ text={`#${contractTerms.order_id}`}
+ kind="neutral"
+ />
+ )}
+ </section>
+ <ButtonsSection />
+ </WalletAction>
+ );
}
function amountToString(text: AmountLike) {
- const aj = Amounts.jsonifyAmount(text)
- const amount = Amounts.stringifyValue(aj, 2)
- return `${amount} ${aj.currency}`
+ const aj = Amounts.jsonifyAmount(text);
+ const amount = Amounts.stringifyValue(aj, 2);
+ return `${amount} ${aj.currency}`;
}
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
index 88e714cb7..a0abcea58 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund.stories.tsx
@@ -15,63 +15,61 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { OrderShortInfo } from '@gnu-taler/taler-util';
-import { createExample } from '../test-utils';
-import { View as TestedComponent } from './Refund';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { OrderShortInfo } from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils";
+import { View as TestedComponent } from "./Refund";
export default {
- title: 'cta/refund',
+ title: "cta/refund",
component: TestedComponent,
- argTypes: {
- },
+ argTypes: {},
};
export const Complete = createExample(TestedComponent, {
applyResult: {
- amountEffectivePaid: 'USD:10',
- amountRefundGone: 'USD:0',
- amountRefundGranted: 'USD:2',
- contractTermsHash: 'QWEASDZXC',
- info: {
- summary: 'tasty cold beer',
- contractTermsHash: 'QWEASDZXC',
- } as Partial<OrderShortInfo> as any,
+ amountEffectivePaid: "USD:10",
+ amountRefundGone: "USD:0",
+ amountRefundGranted: "USD:2",
+ contractTermsHash: "QWEASDZXC",
+ info: ({
+ summary: "tasty cold beer",
+ contractTermsHash: "QWEASDZXC",
+ } as Partial<OrderShortInfo>) as any,
pendingAtExchange: false,
proposalId: "proposal123",
- }
+ },
});
export const Partial = createExample(TestedComponent, {
applyResult: {
- amountEffectivePaid: 'USD:10',
- amountRefundGone: 'USD:1',
- amountRefundGranted: 'USD:2',
- contractTermsHash: 'QWEASDZXC',
- info: {
- summary: 'tasty cold beer',
- contractTermsHash: 'QWEASDZXC',
- } as Partial<OrderShortInfo> as any,
+ amountEffectivePaid: "USD:10",
+ amountRefundGone: "USD:1",
+ amountRefundGranted: "USD:2",
+ contractTermsHash: "QWEASDZXC",
+ info: ({
+ summary: "tasty cold beer",
+ contractTermsHash: "QWEASDZXC",
+ } as Partial<OrderShortInfo>) as any,
pendingAtExchange: false,
proposalId: "proposal123",
- }
+ },
});
export const InProgress = createExample(TestedComponent, {
applyResult: {
- amountEffectivePaid: 'USD:10',
- amountRefundGone: 'USD:1',
- amountRefundGranted: 'USD:2',
- contractTermsHash: 'QWEASDZXC',
- info: {
- summary: 'tasty cold beer',
- contractTermsHash: 'QWEASDZXC',
- } as Partial<OrderShortInfo> as any,
+ amountEffectivePaid: "USD:10",
+ amountRefundGone: "USD:1",
+ amountRefundGranted: "USD:2",
+ contractTermsHash: "QWEASDZXC",
+ info: ({
+ summary: "tasty cold beer",
+ contractTermsHash: "QWEASDZXC",
+ } as Partial<OrderShortInfo>) as any,
pendingAtExchange: true,
proposalId: "proposal123",
- }
+ },
});
diff --git a/packages/taler-wallet-webextension/src/cta/Refund.tsx b/packages/taler-wallet-webextension/src/cta/Refund.tsx
index 943095360..aa11dca6a 100644
--- a/packages/taler-wallet-webextension/src/cta/Refund.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Refund.tsx
@@ -22,45 +22,46 @@
import * as wxApi from "../wxApi";
import { AmountView } from "../renderHtml";
-import {
- ApplyRefundResponse,
- Amounts,
-} from "@gnu-taler/taler-util";
+import { ApplyRefundResponse, Amounts } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
import { JSX } from "preact/jsx-runtime";
-import { h } from 'preact';
+import { h } from "preact";
interface Props {
- talerRefundUri?: string
+ talerRefundUri?: string;
}
export interface ViewProps {
applyResult: ApplyRefundResponse;
}
export function View({ applyResult }: ViewProps) {
- return <section class="main">
- <h1>GNU Taler Wallet</h1>
- <article class="fade">
- <h2>Refund Status</h2>
- <p>
- The product <em>{applyResult.info.summary}</em> has received a total
- effective refund of{" "}
- <AmountView amount={applyResult.amountRefundGranted} />.
- </p>
- {applyResult.pendingAtExchange ? (
- <p>Refund processing is still in progress.</p>
- ) : null}
- {!Amounts.isZero(applyResult.amountRefundGone) ? (
+ return (
+ <section class="main">
+ <h1>GNU Taler Wallet</h1>
+ <article class="fade">
+ <h2>Refund Status</h2>
<p>
- The refund amount of{" "}
- <AmountView amount={applyResult.amountRefundGone} />{" "}
- could not be applied.
+ The product <em>{applyResult.info.summary}</em> has received a total
+ effective refund of{" "}
+ <AmountView amount={applyResult.amountRefundGranted} />.
</p>
- ) : null}
- </article>
- </section>
+ {applyResult.pendingAtExchange ? (
+ <p>Refund processing is still in progress.</p>
+ ) : null}
+ {!Amounts.isZero(applyResult.amountRefundGone) ? (
+ <p>
+ The refund amount of{" "}
+ <AmountView amount={applyResult.amountRefundGone} /> could not be
+ applied.
+ </p>
+ ) : null}
+ </article>
+ </section>
+ );
}
export function RefundPage({ talerRefundUri }: Props): JSX.Element {
- const [applyResult, setApplyResult] = useState<ApplyRefundResponse | undefined>(undefined);
+ const [applyResult, setApplyResult] = useState<
+ ApplyRefundResponse | undefined
+ >(undefined);
const [errMsg, setErrMsg] = useState<string | undefined>(undefined);
useEffect(() => {
diff --git a/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx
index 389b183f0..8da599513 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip.stories.tsx
@@ -15,45 +15,43 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample } from '../test-utils';
-import { View as TestedComponent } from './Tip';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample } from "../test-utils";
+import { View as TestedComponent } from "./Tip";
export default {
- title: 'cta/tip',
+ title: "cta/tip",
component: TestedComponent,
- argTypes: {
- },
+ argTypes: {},
};
export const Accepted = createExample(TestedComponent, {
prepareTipResult: {
accepted: true,
- merchantBaseUrl: '',
- exchangeBaseUrl: '',
- expirationTimestamp : {
- t_ms: 0
+ merchantBaseUrl: "",
+ exchangeBaseUrl: "",
+ expirationTimestamp: {
+ t_ms: 0,
},
- tipAmountEffective: 'USD:10',
- tipAmountRaw: 'USD:5',
- walletTipId: 'id'
- }
+ tipAmountEffective: "USD:10",
+ tipAmountRaw: "USD:5",
+ walletTipId: "id",
+ },
});
export const NotYetAccepted = createExample(TestedComponent, {
prepareTipResult: {
accepted: false,
- merchantBaseUrl: 'http://merchant.url/',
- exchangeBaseUrl: 'http://exchange.url/',
- expirationTimestamp : {
- t_ms: 0
+ merchantBaseUrl: "http://merchant.url/",
+ exchangeBaseUrl: "http://exchange.url/",
+ expirationTimestamp: {
+ t_ms: 0,
},
- tipAmountEffective: 'USD:10',
- tipAmountRaw: 'USD:5',
- walletTipId: 'id'
- }
+ tipAmountEffective: "USD:10",
+ tipAmountRaw: "USD:5",
+ walletTipId: "id",
+ },
});
diff --git a/packages/taler-wallet-webextension/src/cta/Tip.tsx b/packages/taler-wallet-webextension/src/cta/Tip.tsx
index dc1feaed3..0a1c1238c 100644
--- a/packages/taler-wallet-webextension/src/cta/Tip.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Tip.tsx
@@ -25,43 +25,43 @@ import { PrepareTipResult } from "@gnu-taler/taler-util";
import { AmountView } from "../renderHtml";
import * as wxApi from "../wxApi";
import { JSX } from "preact/jsx-runtime";
-import { h } from 'preact';
+import { h } from "preact";
interface Props {
- talerTipUri?: string
+ talerTipUri?: string;
}
export interface ViewProps {
prepareTipResult: PrepareTipResult;
onAccept: () => void;
onIgnore: () => void;
-
}
export function View({ prepareTipResult, onAccept, onIgnore }: ViewProps) {
- return <section class="main">
- <h1>GNU Taler Wallet</h1>
- <article class="fade">
- {prepareTipResult.accepted ? (
- <span>
- Tip from <code>{prepareTipResult.merchantBaseUrl}</code> accepted. Check
- your transactions list for more details.
- </span>
- ) : (
+ return (
+ <section class="main">
+ <h1>GNU Taler Wallet</h1>
+ <article class="fade">
+ {prepareTipResult.accepted ? (
+ <span>
+ Tip from <code>{prepareTipResult.merchantBaseUrl}</code> accepted.
+ Check your transactions list for more details.
+ </span>
+ ) : (
<div>
<p>
The merchant <code>{prepareTipResult.merchantBaseUrl}</code> is
- offering you a tip of{" "}
+ offering you a tip of{" "}
<strong>
<AmountView amount={prepareTipResult.tipAmountEffective} />
</strong>{" "}
- via the exchange <code>{prepareTipResult.exchangeBaseUrl}</code>
+ via the exchange <code>{prepareTipResult.exchangeBaseUrl}</code>
</p>
<button onClick={onAccept}>Accept tip</button>
<button onClick={onIgnore}>Ignore</button>
</div>
)}
- </article>
- </section>
-
+ </article>
+ </section>
+ );
}
export function TipPage({ talerTipUri }: Props): JSX.Element {
@@ -105,7 +105,11 @@ export function TipPage({ talerTipUri }: Props): JSX.Element {
return <span>Loading ...</span>;
}
- return <View prepareTipResult={prepareTipResult}
- onAccept={doAccept} onIgnore={doIgnore}
- />
+ return (
+ <View
+ prepareTipResult={prepareTipResult}
+ onAccept={doAccept}
+ onIgnore={doIgnore}
+ />
+ );
}
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
index 5e29a3e39..90df2a27e 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.stories.tsx
@@ -15,23 +15,22 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { amountFractionalBase, Amounts } from '@gnu-taler/taler-util';
-import { ExchangeRecord } from '@gnu-taler/taler-wallet-core';
-import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw';
-import { getMaxListeners } from 'process';
-import { createExample } from '../test-utils';
-import { View as TestedComponent } from './Withdraw';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { amountFractionalBase, Amounts } from "@gnu-taler/taler-util";
+import { ExchangeRecord } from "@gnu-taler/taler-wallet-core";
+import { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw";
+import { getMaxListeners } from "process";
+import { createExample } from "../test-utils";
+import { View as TestedComponent } from "./Withdraw";
export default {
- title: 'cta/withdraw',
+ title: "cta/withdraw",
component: TestedComponent,
argTypes: {
- onSwitchExchange: { action: 'onRetry' },
+ onSwitchExchange: { action: "onRetry" },
},
};
@@ -48,7 +47,7 @@ const termsHtml = `<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
</div>
</body>
</html>
-`
+`;
const termsPlain = `
Terms Of Service
****************
@@ -432,7 +431,7 @@ Questions or comments
We welcome comments, questions, concerns, or suggestions. Please send
us a message on our contact page at legal@taler-systems.com.
-`
+`;
const termsXml = `<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE document PUBLIC "+//IDN docutils.sourceforge.net//DTD Docutils Generic//EN//XML" "http://docutils.sourceforge.net/docs/ref/docutils.dtd">
@@ -781,120 +780,131 @@ const termsXml = `<?xml version="1.0" encoding="utf-8"?>
`;
export const NewTerms = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'new'
+ status: "new",
},
-})
+});
export const TermsReviewingPLAIN = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'plain',
- content: termsPlain
+ type: "plain",
+ content: termsPlain,
},
- status: 'new'
+ status: "new",
},
- reviewing: true
-})
+ reviewing: true,
+});
export const TermsReviewingHTML = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'html',
- href: new URL(`data:text/html;base64,${Buffer.from(termsHtml).toString('base64')}`),
+ type: "html",
+ href: new URL(
+ `data:text/html;base64,${Buffer.from(termsHtml).toString("base64")}`,
+ ),
},
- status: 'new'
+ status: "new",
},
- reviewing: true
-})
+ reviewing: true,
+});
const termsPdf = `
%PDF-1.2
@@ -909,306 +919,330 @@ endobj
trailer
<< /Root 3 0 R >>
%%EOF
-`
+`;
export const TermsReviewingPDF = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'pdf',
- location: new URL(`data:text/html;base64,${Buffer.from(termsPdf).toString('base64')}`),
+ type: "pdf",
+ location: new URL(
+ `data:text/html;base64,${Buffer.from(termsPdf).toString("base64")}`,
+ ),
},
- status: 'new'
+ status: "new",
},
- reviewing: true
-})
-
+ reviewing: true,
+});
export const TermsReviewingXML = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'new'
+ status: "new",
},
- reviewing: true
-})
+ reviewing: true,
+});
export const NewTermsAccepted = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'new'
+ status: "new",
},
- reviewed: true
-})
+ reviewed: true,
+});
export const TermsShowAgainXML = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'new'
+ status: "new",
},
reviewed: true,
reviewing: true,
-})
+});
export const TermsChanged = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'changed'
+ status: "changed",
},
-})
+});
export const TermsNotFound = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
- status: 'notfound'
+ status: "notfound",
},
-})
+});
export const TermsAlreadyAccepted = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: amountFractionalBase * 0.5,
- value: 0
+ value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
- status: 'accepted'
+ status: "accepted",
},
-})
-
+});
export const WithoutFee = createExample(TestedComponent, {
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'exchange.demo.taler.net',
- paytoUris: ['asd'],
- }, {
- currency: 'USD',
- exchangeBaseUrl: 'exchange.test.taler.net',
- paytoUris: ['asd'],
- }],
- exchangeBaseUrl: 'exchange.demo.taler.net',
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.demo.taler.net",
+ paytoUris: ["asd"],
+ },
+ {
+ currency: "USD",
+ exchangeBaseUrl: "exchange.test.taler.net",
+ paytoUris: ["asd"],
+ },
+ ],
+ exchangeBaseUrl: "exchange.demo.taler.net",
details: {
- content: '',
- contentType: '',
- currentEtag: '',
+ content: "",
+ contentType: "",
+ currentEtag: "",
acceptedEtag: undefined,
},
withdrawalFee: {
- currency: 'USD',
+ currency: "USD",
fraction: 0,
value: 0,
},
amount: {
- currency: 'USD',
+ currency: "USD",
value: 2,
- fraction: 10000000
+ fraction: 10000000,
},
- onSwitchExchange: async () => { },
+ onSwitchExchange: async () => {},
terms: {
value: {
- type: 'xml',
+ type: "xml",
document: new DOMParser().parseFromString(termsXml, "text/xml"),
},
- status: 'accepted',
- }
-}) \ No newline at end of file
+ status: "accepted",
+ },
+});
diff --git a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
index 6ef72cbe6..603dafcde 100644
--- a/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
+++ b/packages/taler-wallet-webextension/src/cta/Withdraw.tsx
@@ -21,21 +21,39 @@
* @author Florian Dold
*/
-import { AmountJson, Amounts, ExchangeListItem, GetExchangeTosResult, i18n, WithdrawUriInfoResponse } from '@gnu-taler/taler-util';
-import { ExchangeWithdrawDetails } from '@gnu-taler/taler-wallet-core/src/operations/withdraw';
+import {
+ AmountJson,
+ Amounts,
+ ExchangeListItem,
+ GetExchangeTosResult,
+ i18n,
+ WithdrawUriInfoResponse,
+} from "@gnu-taler/taler-util";
+import { VNode, h } from "preact";
import { useState } from "preact/hooks";
-import { Fragment } from 'preact/jsx-runtime';
-import { CheckboxOutlined } from '../components/CheckboxOutlined';
-import { ExchangeXmlTos } from '../components/ExchangeToS';
-import { LogoHeader } from '../components/LogoHeader';
-import { Part } from '../components/Part';
-import { SelectList } from '../components/SelectList';
-import { ButtonSuccess, ButtonWarning, LinkSuccess, LinkWarning, TermsOfService, WalletAction, WarningText } from '../components/styled';
-import { useAsyncAsHook } from '../hooks/useAsyncAsHook';
+import { Fragment } from "preact/jsx-runtime";
+import { CheckboxOutlined } from "../components/CheckboxOutlined";
+import { ExchangeXmlTos } from "../components/ExchangeToS";
+import { LogoHeader } from "../components/LogoHeader";
+import { Part } from "../components/Part";
+import { SelectList } from "../components/SelectList";
+import {
+ ButtonSuccess,
+ ButtonWarning,
+ LinkSuccess,
+ TermsOfService,
+ WalletAction,
+ WarningText,
+} from "../components/styled";
+import { useAsyncAsHook } from "../hooks/useAsyncAsHook";
import {
- acceptWithdrawal, getExchangeWithdrawalInfo, getWithdrawalDetailsForUri, setExchangeTosAccepted, listExchanges, getExchangeTos
+ acceptWithdrawal,
+ getExchangeTos,
+ getExchangeWithdrawalInfo,
+ getWithdrawalDetailsForUri,
+ listExchanges,
+ setExchangeTosAccepted,
} from "../wxApi";
-import { wxMain } from '../wxBackend.js';
interface Props {
talerWithdrawUri?: string;
@@ -58,145 +76,193 @@ export interface ViewProps {
status: TermsStatus;
};
knownExchanges: ExchangeListItem[];
+}
-};
-
-type TermsStatus = 'new' | 'accepted' | 'changed' | 'notfound';
+type TermsStatus = "new" | "accepted" | "changed" | "notfound";
-type TermsDocument = TermsDocumentXml | TermsDocumentHtml | TermsDocumentPlain | TermsDocumentJson | TermsDocumentPdf;
+type TermsDocument =
+ | TermsDocumentXml
+ | TermsDocumentHtml
+ | TermsDocumentPlain
+ | TermsDocumentJson
+ | TermsDocumentPdf;
interface TermsDocumentXml {
- type: 'xml',
- document: Document,
+ type: "xml";
+ document: Document;
}
interface TermsDocumentHtml {
- type: 'html',
- href: URL,
+ type: "html";
+ href: URL;
}
interface TermsDocumentPlain {
- type: 'plain',
- content: string,
+ type: "plain";
+ content: string;
}
interface TermsDocumentJson {
- type: 'json',
- data: any,
+ type: "json";
+ data: any;
}
interface TermsDocumentPdf {
- type: 'pdf',
- location: URL,
+ type: "pdf";
+ location: URL;
}
function amountToString(text: AmountJson) {
- const aj = Amounts.jsonifyAmount(text)
- const amount = Amounts.stringifyValue(aj)
- return `${amount} ${aj.currency}`
+ const aj = Amounts.jsonifyAmount(text);
+ const amount = Amounts.stringifyValue(aj);
+ return `${amount} ${aj.currency}`;
}
-export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges, amount, onWithdraw, onSwitchExchange, terms, reviewing, onReview, onAccept, reviewed, confirmed }: ViewProps) {
- const needsReview = terms.status === 'changed' || terms.status === 'new'
-
- const [switchingExchange, setSwitchingExchange] = useState<string | undefined>(undefined)
- const exchanges = knownExchanges.reduce((prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }), {})
+export function View({
+ details,
+ withdrawalFee,
+ exchangeBaseUrl,
+ knownExchanges,
+ amount,
+ onWithdraw,
+ onSwitchExchange,
+ terms,
+ reviewing,
+ onReview,
+ onAccept,
+ reviewed,
+ confirmed,
+}: ViewProps) {
+ const needsReview = terms.status === "changed" || terms.status === "new";
+
+ const [switchingExchange, setSwitchingExchange] = useState<
+ string | undefined
+ >(undefined);
+ const exchanges = knownExchanges.reduce(
+ (prev, ex) => ({ ...prev, [ex.exchangeBaseUrl]: ex.exchangeBaseUrl }),
+ {},
+ );
return (
<WalletAction>
<LogoHeader />
- <h2>
- {i18n.str`Digital cash withdrawal`}
- </h2>
+ <h2>{i18n.str`Digital cash withdrawal`}</h2>
<section>
- <Part title="Total to withdraw" text={amountToString(Amounts.sub(amount, withdrawalFee).amount)} kind='positive' />
- <Part title="Chosen amount" text={amountToString(amount)} kind='neutral' />
- {Amounts.isNonZero(withdrawalFee) &&
- <Part title="Exchange fee" text={amountToString(withdrawalFee)} kind='negative' />
- }
- <Part title="Exchange" text={exchangeBaseUrl} kind='neutral' big />
+ <Part
+ title="Total to withdraw"
+ text={amountToString(Amounts.sub(amount, withdrawalFee).amount)}
+ kind="positive"
+ />
+ <Part
+ title="Chosen amount"
+ text={amountToString(amount)}
+ kind="neutral"
+ />
+ {Amounts.isNonZero(withdrawalFee) && (
+ <Part
+ title="Exchange fee"
+ text={amountToString(withdrawalFee)}
+ kind="negative"
+ />
+ )}
+ <Part title="Exchange" text={exchangeBaseUrl} kind="neutral" big />
</section>
- {!reviewing &&
+ {!reviewing && (
<section>
- {switchingExchange !== undefined ? <Fragment>
- <div>
- <SelectList label="Known exchanges" list={exchanges} name="" onChange={onSwitchExchange} />
- </div>
- <LinkSuccess upperCased onClick={() => onSwitchExchange(switchingExchange)}>
- {i18n.str`Confirm exchange selection`}
- </LinkSuccess>
- </Fragment>
- : <LinkSuccess upperCased onClick={() => setSwitchingExchange("")}>
+ {switchingExchange !== undefined ? (
+ <Fragment>
+ <div>
+ <SelectList
+ label="Known exchanges"
+ list={exchanges}
+ name=""
+ onChange={onSwitchExchange}
+ />
+ </div>
+ <LinkSuccess
+ upperCased
+ onClick={() => onSwitchExchange(switchingExchange)}
+ >
+ {i18n.str`Confirm exchange selection`}
+ </LinkSuccess>
+ </Fragment>
+ ) : (
+ <LinkSuccess upperCased onClick={() => setSwitchingExchange("")}>
{i18n.str`Switch exchange`}
- </LinkSuccess>}
-
+ </LinkSuccess>
+ )}
</section>
- }
- {!reviewing && reviewed &&
+ )}
+ {!reviewing && reviewed && (
<section>
- <LinkSuccess
- upperCased
- onClick={() => onReview(true)}
- >
+ <LinkSuccess upperCased onClick={() => onReview(true)}>
{i18n.str`Show terms of service`}
</LinkSuccess>
</section>
- }
- {terms.status === 'notfound' &&
+ )}
+ {terms.status === "notfound" && (
<section>
<WarningText>
{i18n.str`Exchange doesn't have terms of service`}
</WarningText>
</section>
- }
- {reviewing &&
+ )}
+ {reviewing && (
<section>
- {terms.status !== 'accepted' && terms.value && terms.value.type === 'xml' &&
- <TermsOfService>
- <ExchangeXmlTos doc={terms.value.document} />
- </TermsOfService>
- }
- {terms.status !== 'accepted' && terms.value && terms.value.type === 'plain' &&
- <div style={{ textAlign: 'left' }}>
- <pre>{terms.value.content}</pre>
- </div>
- }
- {terms.status !== 'accepted' && terms.value && terms.value.type === 'html' &&
- <iframe src={terms.value.href.toString()} />
- }
- {terms.status !== 'accepted' && terms.value && terms.value.type === 'pdf' &&
- <a href={terms.value.location.toString()} download="tos.pdf" >Download Terms of Service</a>
- }
- </section>}
- {reviewing && reviewed &&
+ {terms.status !== "accepted" &&
+ terms.value &&
+ terms.value.type === "xml" && (
+ <TermsOfService>
+ <ExchangeXmlTos doc={terms.value.document} />
+ </TermsOfService>
+ )}
+ {terms.status !== "accepted" &&
+ terms.value &&
+ terms.value.type === "plain" && (
+ <div style={{ textAlign: "left" }}>
+ <pre>{terms.value.content}</pre>
+ </div>
+ )}
+ {terms.status !== "accepted" &&
+ terms.value &&
+ terms.value.type === "html" && (
+ <iframe src={terms.value.href.toString()} />
+ )}
+ {terms.status !== "accepted" &&
+ terms.value &&
+ terms.value.type === "pdf" && (
+ <a href={terms.value.location.toString()} download="tos.pdf">
+ Download Terms of Service
+ </a>
+ )}
+ </section>
+ )}
+ {reviewing && reviewed && (
<section>
- <LinkSuccess
- upperCased
- onClick={() => onReview(false)}
- >
+ <LinkSuccess upperCased onClick={() => onReview(false)}>
{i18n.str`Hide terms of service`}
</LinkSuccess>
</section>
- }
- {(reviewing || reviewed) &&
+ )}
+ {(reviewing || reviewed) && (
<section>
<CheckboxOutlined
name="terms"
enabled={reviewed}
label={i18n.str`I accept the exchange terms of service`}
onToggle={() => {
- onAccept(!reviewed)
- onReview(false)
+ onAccept(!reviewed);
+ onReview(false);
}}
/>
</section>
- }
+ )}
{/**
* Main action section
*/}
<section>
- {terms.status === 'new' && !reviewed && !reviewing &&
+ {terms.status === "new" && !reviewed && !reviewing && (
<ButtonSuccess
upperCased
disabled={!exchangeBaseUrl}
@@ -204,8 +270,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges,
>
{i18n.str`Review exchange terms of service`}
</ButtonSuccess>
- }
- {terms.status === 'changed' && !reviewed && !reviewing &&
+ )}
+ {terms.status === "changed" && !reviewed && !reviewing && (
<ButtonWarning
upperCased
disabled={!exchangeBaseUrl}
@@ -213,8 +279,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges,
>
{i18n.str`Review new version of terms of service`}
</ButtonWarning>
- }
- {(terms.status === 'accepted' || (needsReview && reviewed)) &&
+ )}
+ {(terms.status === "accepted" || (needsReview && reviewed)) && (
<ButtonSuccess
upperCased
disabled={!exchangeBaseUrl || confirmed}
@@ -222,8 +288,8 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges,
>
{i18n.str`Confirm withdrawal`}
</ButtonSuccess>
- }
- {terms.status === 'notfound' &&
+ )}
+ {terms.status === "notfound" && (
<ButtonWarning
upperCased
disabled={!exchangeBaseUrl}
@@ -231,60 +297,88 @@ export function View({ details, withdrawalFee, exchangeBaseUrl, knownExchanges,
>
{i18n.str`Withdraw anyway`}
</ButtonWarning>
- }
+ )}
</section>
</WalletAction>
- )
+ );
}
-export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriInfo: WithdrawUriInfoResponse }) {
- const [customExchange, setCustomExchange] = useState<string | undefined>(undefined)
- const [errorAccepting, setErrorAccepting] = useState<string | undefined>(undefined)
-
- const [reviewing, setReviewing] = useState<boolean>(false)
- const [reviewed, setReviewed] = useState<boolean>(false)
- const [confirmed, setConfirmed] = useState<boolean>(false)
-
- const knownExchangesHook = useAsyncAsHook(() => listExchanges())
-
- const knownExchanges = !knownExchangesHook || knownExchangesHook.hasError ? [] : knownExchangesHook.response.exchanges
- const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount)
- const thisCurrencyExchanges = knownExchanges.filter(ex => ex.currency === withdrawAmount.currency)
-
- const exchange = customExchange || uriInfo.defaultExchangeBaseUrl || thisCurrencyExchanges[0]?.exchangeBaseUrl
+export function WithdrawPageWithParsedURI({
+ uri,
+ uriInfo,
+}: {
+ uri: string;
+ uriInfo: WithdrawUriInfoResponse;
+}) {
+ const [customExchange, setCustomExchange] = useState<string | undefined>(
+ undefined,
+ );
+ const [errorAccepting, setErrorAccepting] = useState<string | undefined>(
+ undefined,
+ );
+
+ const [reviewing, setReviewing] = useState<boolean>(false);
+ const [reviewed, setReviewed] = useState<boolean>(false);
+ const [confirmed, setConfirmed] = useState<boolean>(false);
+
+ const knownExchangesHook = useAsyncAsHook(() => listExchanges());
+
+ const knownExchanges =
+ !knownExchangesHook || knownExchangesHook.hasError
+ ? []
+ : knownExchangesHook.response.exchanges;
+ const withdrawAmount = Amounts.parseOrThrow(uriInfo.amount);
+ const thisCurrencyExchanges = knownExchanges.filter(
+ (ex) => ex.currency === withdrawAmount.currency,
+ );
+
+ const exchange =
+ customExchange ||
+ uriInfo.defaultExchangeBaseUrl ||
+ thisCurrencyExchanges[0]?.exchangeBaseUrl;
const detailsHook = useAsyncAsHook(async () => {
- if (!exchange) throw Error('no default exchange')
- const tos = await getExchangeTos(exchange, ['text/xml'])
+ if (!exchange) throw Error("no default exchange");
+ const tos = await getExchangeTos(exchange, ["text/xml"]);
const info = await getExchangeWithdrawalInfo({
exchangeBaseUrl: exchange,
amount: withdrawAmount,
- tosAcceptedFormat: ['text/xml']
- })
- return { tos, info }
- })
+ tosAcceptedFormat: ["text/xml"],
+ });
+ return { tos, info };
+ });
if (!detailsHook) {
- return <span><i18n.Translate>Getting withdrawal details.</i18n.Translate></span>;
+ return (
+ <span>
+ <i18n.Translate>Getting withdrawal details.</i18n.Translate>
+ </span>
+ );
}
if (detailsHook.hasError) {
- return <span><i18n.Translate>Problems getting details: {detailsHook.message}</i18n.Translate></span>;
+ return (
+ <span>
+ <i18n.Translate>
+ Problems getting details: {detailsHook.message}
+ </i18n.Translate>
+ </span>
+ );
}
- const details = detailsHook.response
+ const details = detailsHook.response;
const onAccept = async (): Promise<void> => {
try {
- await setExchangeTosAccepted(exchange, details.tos.currentEtag)
- setReviewed(true)
+ await setExchangeTosAccepted(exchange, details.tos.currentEtag);
+ setReviewed(true);
} catch (e) {
if (e instanceof Error) {
- setErrorAccepting(e.message)
+ setErrorAccepting(e.message);
}
}
- }
+ };
const onWithdraw = async (): Promise<void> => {
- setConfirmed(true)
+ setConfirmed(true);
console.log("accepting exchange", exchange);
try {
const res = await acceptWithdrawal(uri, exchange);
@@ -293,91 +387,121 @@ export function WithdrawPageWithParsedURI({ uri, uriInfo }: { uri: string, uriIn
document.location.href = res.confirmTransferUrl;
}
} catch (e) {
- setConfirmed(false)
+ setConfirmed(false);
}
};
- const termsContent: TermsDocument | undefined = parseTermsOfServiceContent(details.tos.contentType, details.tos.content);
-
- const status: TermsStatus = !termsContent ? 'notfound' : (
- !details.tos.acceptedEtag ? 'new' : (
- details.tos.acceptedEtag !== details.tos.currentEtag ? 'changed' : 'accepted'
- ))
-
-
- return <View onWithdraw={onWithdraw}
- details={details.tos} amount={withdrawAmount}
- exchangeBaseUrl={exchange}
- withdrawalFee={details.info.withdrawFee} //FIXME
- terms={{
- status, value: termsContent
- }}
- onSwitchExchange={setCustomExchange}
- knownExchanges={knownExchanges}
- confirmed={confirmed}
- reviewed={reviewed} onAccept={onAccept}
- reviewing={reviewing} onReview={setReviewing}
- />
+ const termsContent: TermsDocument | undefined = parseTermsOfServiceContent(
+ details.tos.contentType,
+ details.tos.content,
+ );
+
+ const status: TermsStatus = !termsContent
+ ? "notfound"
+ : !details.tos.acceptedEtag
+ ? "new"
+ : details.tos.acceptedEtag !== details.tos.currentEtag
+ ? "changed"
+ : "accepted";
+
+ return (
+ <View
+ onWithdraw={onWithdraw}
+ details={details.tos}
+ amount={withdrawAmount}
+ exchangeBaseUrl={exchange}
+ withdrawalFee={details.info.withdrawFee} //FIXME
+ terms={{
+ status,
+ value: termsContent,
+ }}
+ onSwitchExchange={setCustomExchange}
+ knownExchanges={knownExchanges}
+ confirmed={confirmed}
+ reviewed={reviewed}
+ onAccept={onAccept}
+ reviewing={reviewing}
+ onReview={setReviewing}
+ />
+ );
}
-export function WithdrawPage({ talerWithdrawUri }: Props): JSX.Element {
- const uriInfoHook = useAsyncAsHook(() => !talerWithdrawUri ? Promise.reject(undefined) :
- getWithdrawalDetailsForUri({ talerWithdrawUri })
- )
+export function WithdrawPage({ talerWithdrawUri }: Props): VNode {
+ const uriInfoHook = useAsyncAsHook(() =>
+ !talerWithdrawUri
+ ? Promise.reject(undefined)
+ : getWithdrawalDetailsForUri({ talerWithdrawUri }),
+ );
if (!talerWithdrawUri) {
- return <span><i18n.Translate>missing withdraw uri</i18n.Translate></span>;
+ return (
+ <span>
+ <i18n.Translate>missing withdraw uri</i18n.Translate>
+ </span>
+ );
}
if (!uriInfoHook) {
- return <span><i18n.Translate>Loading...</i18n.Translate></span>;
+ return (
+ <span>
+ <i18n.Translate>Loading...</i18n.Translate>
+ </span>
+ );
}
if (uriInfoHook.hasError) {
- return <span><i18n.Translate>This URI is not valid anymore: {uriInfoHook.message}</i18n.Translate></span>;
+ return (
+ <span>
+ <i18n.Translate>
+ This URI is not valid anymore: {uriInfoHook.message}
+ </i18n.Translate>
+ </span>
+ );
}
- return <WithdrawPageWithParsedURI uri={talerWithdrawUri} uriInfo={uriInfoHook.response} />
+ return (
+ <WithdrawPageWithParsedURI
+ uri={talerWithdrawUri}
+ uriInfo={uriInfoHook.response}
+ />
+ );
}
-function parseTermsOfServiceContent(type: string, text: string): TermsDocument | undefined {
- if (type === 'text/xml') {
+function parseTermsOfServiceContent(
+ type: string,
+ text: string,
+): TermsDocument | undefined {
+ if (type === "text/xml") {
try {
- const document = new DOMParser().parseFromString(text, "text/xml")
- return { type: 'xml', document }
+ const document = new DOMParser().parseFromString(text, "text/xml");
+ return { type: "xml", document };
} catch (e) {
- console.log(e)
- debugger;
+ console.log(e);
}
- } else if (type === 'text/html') {
+ } else if (type === "text/html") {
try {
- const href = new URL(text)
- return { type: 'html', href }
+ const href = new URL(text);
+ return { type: "html", href };
} catch (e) {
- console.log(e)
- debugger;
+ console.log(e);
}
- } else if (type === 'text/json') {
+ } else if (type === "text/json") {
try {
- const data = JSON.parse(text)
- return { type: 'json', data }
+ const data = JSON.parse(text);
+ return { type: "json", data };
} catch (e) {
- console.log(e)
- debugger;
+ console.log(e);
}
- } else if (type === 'text/pdf') {
+ } else if (type === "text/pdf") {
try {
- const location = new URL(text)
- return { type: 'pdf', location }
+ const location = new URL(text);
+ return { type: "pdf", location };
} catch (e) {
- console.log(e)
- debugger;
+ console.log(e);
}
- } else if (type === 'text/plain') {
+ } else if (type === "text/plain") {
try {
- const content = text
- return { type: 'plain', content }
+ const content = text;
+ return { type: "plain", content };
} catch (e) {
- console.log(e)
- debugger;
+ console.log(e);
}
}
- return undefined
+ return undefined;
}
-
diff --git a/packages/taler-wallet-webextension/src/cta/payback.tsx b/packages/taler-wallet-webextension/src/cta/payback.tsx
index 1e27fd912..60cb8c513 100644
--- a/packages/taler-wallet-webextension/src/cta/payback.tsx
+++ b/packages/taler-wallet-webextension/src/cta/payback.tsx
@@ -15,7 +15,7 @@
*/
import { JSX } from "preact/jsx-runtime";
-import { h } from 'preact';
+import { h } from "preact";
/**
* View and edit auditors.
diff --git a/packages/taler-wallet-webextension/src/cta/reset-required.tsx b/packages/taler-wallet-webextension/src/cta/reset-required.tsx
index e66c0db57..3949318c4 100644
--- a/packages/taler-wallet-webextension/src/cta/reset-required.tsx
+++ b/packages/taler-wallet-webextension/src/cta/reset-required.tsx
@@ -63,7 +63,7 @@ class ResetNotification extends Component<any, State> {
type="checkbox"
checked={this.state.checked}
onChange={() => {
- this.setState(prev => ({ checked: prev.checked }))
+ this.setState((prev) => ({ checked: prev.checked }));
}}
/>{" "}
<label htmlFor="check">
diff --git a/packages/taler-wallet-webextension/src/cta/return-coins.tsx b/packages/taler-wallet-webextension/src/cta/return-coins.tsx
index 43d73b5fe..548202cab 100644
--- a/packages/taler-wallet-webextension/src/cta/return-coins.tsx
+++ b/packages/taler-wallet-webextension/src/cta/return-coins.tsx
@@ -15,7 +15,7 @@
*/
import { JSX } from "preact/jsx-runtime";
-import { h } from 'preact';
+import { h } from "preact";
/**
* Return coins to own bank account.
*
diff --git a/packages/taler-wallet-webextension/src/custom.d.ts b/packages/taler-wallet-webextension/src/custom.d.ts
index 1981067d4..521b824c7 100644
--- a/packages/taler-wallet-webextension/src/custom.d.ts
+++ b/packages/taler-wallet-webextension/src/custom.d.ts
@@ -21,7 +21,7 @@ declare module "*.png" {
const content: any;
export default content;
}
-declare module '*.svg' {
+declare module "*.svg" {
const content: any;
export default content;
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
index 2131d45cb..aa6695c3e 100644
--- a/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useAsyncAsHook.ts
@@ -29,7 +29,7 @@ interface HookError {
export type HookResponse<T> = HookOk<T> | HookError | undefined;
-export function useAsyncAsHook<T> (fn: (() => Promise<T>)): HookResponse<T> {
+export function useAsyncAsHook<T>(fn: () => Promise<T>): HookResponse<T> {
const [result, setHookResponse] = useState<HookResponse<T>>(undefined);
useEffect(() => {
async function doAsync() {
@@ -42,7 +42,7 @@ export function useAsyncAsHook<T> (fn: (() => Promise<T>)): HookResponse<T> {
}
}
}
- doAsync()
+ doAsync();
}, []);
return result;
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts b/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
index f3b1b3b5f..1aa711a90 100644
--- a/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useBackupDeviceName.ts
@@ -17,34 +17,31 @@
import { useEffect, useState } from "preact/hooks";
import * as wxApi from "../wxApi";
-
export interface BackupDeviceName {
name: string;
- update: (s:string) => Promise<void>
+ update: (s: string) => Promise<void>;
}
-
export function useBackupDeviceName(): BackupDeviceName {
const [status, setStatus] = useState<BackupDeviceName>({
- name: '',
- update: () => Promise.resolve()
- })
+ name: "",
+ update: () => Promise.resolve(),
+ });
useEffect(() => {
async function run() {
//create a first list of backup info by currency
- const status = await wxApi.getBackupInfo()
+ const status = await wxApi.getBackupInfo();
async function update(newName: string) {
- await wxApi.setWalletDeviceId(newName)
- setStatus(old => ({ ...old, name: newName }))
+ await wxApi.setWalletDeviceId(newName);
+ setStatus((old) => ({ ...old, name: newName }));
}
- setStatus({ name: status.deviceId, update })
+ setStatus({ name: status.deviceId, update });
}
- run()
- }, [])
+ run();
+ }, []);
- return status
+ return status;
}
-
diff --git a/packages/taler-wallet-webextension/src/hooks/useBackupStatus.ts b/packages/taler-wallet-webextension/src/hooks/useBackupStatus.ts
index c46ab6a5f..8a8fd6f2f 100644
--- a/packages/taler-wallet-webextension/src/hooks/useBackupStatus.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useBackupStatus.ts
@@ -14,11 +14,15 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { ProviderInfo, ProviderPaymentPaid, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import {
+ ProviderInfo,
+ ProviderPaymentPaid,
+ ProviderPaymentStatus,
+ ProviderPaymentType,
+} from "@gnu-taler/taler-wallet-core";
import { useEffect, useState } from "preact/hooks";
import * as wxApi from "../wxApi";
-
export interface BackupStatus {
deviceName: string;
providers: ProviderInfo[];
@@ -32,40 +36,46 @@ function getStatusTypeOrder(t: ProviderPaymentStatus) {
ProviderPaymentType.Unpaid,
ProviderPaymentType.Paid,
ProviderPaymentType.Pending,
- ].indexOf(t.type)
+ ].indexOf(t.type);
}
function getStatusPaidOrder(a: ProviderPaymentPaid, b: ProviderPaymentPaid) {
- return a.paidUntil.t_ms === 'never' ? -1 :
- b.paidUntil.t_ms === 'never' ? 1 :
- a.paidUntil.t_ms - b.paidUntil.t_ms
+ return a.paidUntil.t_ms === "never"
+ ? -1
+ : b.paidUntil.t_ms === "never"
+ ? 1
+ : a.paidUntil.t_ms - b.paidUntil.t_ms;
}
export function useBackupStatus(): BackupStatus | undefined {
- const [status, setStatus] = useState<BackupStatus | undefined>(undefined)
+ const [status, setStatus] = useState<BackupStatus | undefined>(undefined);
useEffect(() => {
async function run() {
//create a first list of backup info by currency
- const status = await wxApi.getBackupInfo()
+ const status = await wxApi.getBackupInfo();
const providers = status.providers.sort((a, b) => {
- if (a.paymentStatus.type === ProviderPaymentType.Paid && b.paymentStatus.type === ProviderPaymentType.Paid) {
- return getStatusPaidOrder(a.paymentStatus, b.paymentStatus)
+ if (
+ a.paymentStatus.type === ProviderPaymentType.Paid &&
+ b.paymentStatus.type === ProviderPaymentType.Paid
+ ) {
+ return getStatusPaidOrder(a.paymentStatus, b.paymentStatus);
}
- return getStatusTypeOrder(a.paymentStatus) - getStatusTypeOrder(b.paymentStatus)
- })
+ return (
+ getStatusTypeOrder(a.paymentStatus) -
+ getStatusTypeOrder(b.paymentStatus)
+ );
+ });
async function sync() {
- await wxApi.syncAllProviders()
+ await wxApi.syncAllProviders();
}
-
- setStatus({ deviceName: status.deviceId, providers, sync })
+
+ setStatus({ deviceName: status.deviceId, providers, sync });
}
- run()
- }, [])
+ run();
+ }, []);
- return status
+ return status;
}
-
-
diff --git a/packages/taler-wallet-webextension/src/hooks/useBalances.ts b/packages/taler-wallet-webextension/src/hooks/useBalances.ts
index 37424fb05..403ce7b87 100644
--- a/packages/taler-wallet-webextension/src/hooks/useBalances.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useBalances.ts
@@ -18,7 +18,6 @@ import { BalancesResponse } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
import * as wxApi from "../wxApi";
-
interface BalancesHookOk {
hasError: false;
response: BalancesResponse;
@@ -46,7 +45,7 @@ export function useBalances(): BalancesHook {
}
}
}
- checkBalance()
+ checkBalance();
return wxApi.onUpdateNotification(checkBalance);
}, []);
diff --git a/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts b/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
index 888d4d5f1..48aff2602 100644
--- a/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useDiagnostics.ts
@@ -21,7 +21,7 @@ import * as wxApi from "../wxApi";
export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
const [timedOut, setTimedOut] = useState(false);
const [diagnostics, setDiagnostics] = useState<WalletDiagnostics | undefined>(
- undefined
+ undefined,
);
useEffect(() => {
@@ -41,5 +41,5 @@ export function useDiagnostics(): [WalletDiagnostics | undefined, boolean] {
console.log("fetching diagnostics");
doFetch();
}, []);
- return [diagnostics, timedOut]
-} \ No newline at end of file
+ return [diagnostics, timedOut];
+}
diff --git a/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts b/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts
index a92425760..aaab0aa43 100644
--- a/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useExtendedPermissions.ts
@@ -19,13 +19,12 @@ import * as wxApi from "../wxApi";
import { getPermissionsApi } from "../compat";
import { extendedPermissions } from "../permissions";
-
export function useExtendedPermissions(): [boolean, () => void] {
const [enabled, setEnabled] = useState(false);
const toggle = () => {
- setEnabled(v => !v);
- handleExtendedPerm(enabled).then(result => {
+ setEnabled((v) => !v);
+ handleExtendedPerm(enabled).then((result) => {
setEnabled(result);
});
};
@@ -65,5 +64,5 @@ async function handleExtendedPerm(isEnabled: boolean): Promise<boolean> {
nextVal = res.newValue;
}
console.log("new permissions applied:", nextVal ?? false);
- return nextVal ?? false
-} \ No newline at end of file
+ return nextVal ?? false;
+}
diff --git a/packages/taler-wallet-webextension/src/hooks/useLang.ts b/packages/taler-wallet-webextension/src/hooks/useLang.ts
index 70b9614f6..cc4ff3fc8 100644
--- a/packages/taler-wallet-webextension/src/hooks/useLang.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useLang.ts
@@ -14,10 +14,13 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { useNotNullLocalStorage } from './useLocalStorage';
+import { useNotNullLocalStorage } from "./useLocalStorage";
-export function useLang(initial?: string): [string, (s:string) => void] {
- const browserLang: string | undefined = typeof window !== "undefined" ? navigator.language || (navigator as any).userLanguage : undefined;
- const defaultLang = (browserLang || initial || 'en').substring(0, 2)
- return useNotNullLocalStorage('lang-preference', defaultLang)
+export function useLang(initial?: string): [string, (s: string) => void] {
+ const browserLang: string | undefined =
+ typeof window !== "undefined"
+ ? navigator.language || (navigator as any).userLanguage
+ : undefined;
+ const defaultLang = (browserLang || initial || "en").substring(0, 2);
+ return useNotNullLocalStorage("lang-preference", defaultLang);
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
index 78a8b65d5..3883aff04 100644
--- a/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useLocalStorage.ts
@@ -15,38 +15,52 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import { StateUpdater, useState } from "preact/hooks";
-export function useLocalStorage(key: string, initialValue?: string): [string | undefined, StateUpdater<string | undefined>] {
- const [storedValue, setStoredValue] = useState<string | undefined>((): string | undefined => {
- return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
+export function useLocalStorage(
+ key: string,
+ initialValue?: string,
+): [string | undefined, StateUpdater<string | undefined>] {
+ const [storedValue, setStoredValue] = useState<string | undefined>(():
+ | string
+ | undefined => {
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
});
- const setValue = (value?: string | ((val?: string) => string | undefined)) => {
- setStoredValue(p => {
- const toStore = value instanceof Function ? value(p) : value
+ const setValue = (
+ value?: string | ((val?: string) => string | undefined),
+ ) => {
+ setStoredValue((p) => {
+ const toStore = value instanceof Function ? value(p) : value;
if (typeof window !== "undefined") {
if (!toStore) {
- window.localStorage.removeItem(key)
+ window.localStorage.removeItem(key);
} else {
window.localStorage.setItem(key, toStore);
}
}
- return toStore
- })
+ return toStore;
+ });
};
return [storedValue, setValue];
}
//TODO: merge with the above function
-export function useNotNullLocalStorage(key: string, initialValue: string): [string, StateUpdater<string>] {
+export function useNotNullLocalStorage(
+ key: string,
+ initialValue: string,
+): [string, StateUpdater<string>] {
const [storedValue, setStoredValue] = useState<string>((): string => {
- return typeof window !== "undefined" ? window.localStorage.getItem(key) || initialValue : initialValue;
+ return typeof window !== "undefined"
+ ? window.localStorage.getItem(key) || initialValue
+ : initialValue;
});
const setValue = (value: string | ((val: string) => string)) => {
@@ -54,7 +68,7 @@ export function useNotNullLocalStorage(key: string, initialValue: string): [stri
setStoredValue(valueToStore);
if (typeof window !== "undefined") {
if (!valueToStore) {
- window.localStorage.removeItem(key)
+ window.localStorage.removeItem(key);
} else {
window.localStorage.setItem(key, valueToStore);
}
diff --git a/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts b/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
index 6520848a5..ea167463e 100644
--- a/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useProviderStatus.ts
@@ -32,7 +32,9 @@ export function useProviderStatus(url: string): ProviderStatus | undefined {
//create a first list of backup info by currency
const status = await wxApi.getBackupInfo();
- const providers = status.providers.filter(p => p.syncProviderBaseUrl === url);
+ const providers = status.providers.filter(
+ (p) => p.syncProviderBaseUrl === url,
+ );
const info = providers.length ? providers[0] : undefined;
async function sync() {
diff --git a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts
index ff9cc029a..96a278401 100644
--- a/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts
+++ b/packages/taler-wallet-webextension/src/hooks/useTalerActionURL.ts
@@ -17,15 +17,18 @@
import { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
import { useEffect, useState } from "preact/hooks";
-export function useTalerActionURL(): [string | undefined, (s: boolean) => void] {
+export function useTalerActionURL(): [
+ string | undefined,
+ (s: boolean) => void,
+] {
const [talerActionUrl, setTalerActionUrl] = useState<string | undefined>(
- undefined
+ undefined,
);
const [dismissed, setDismissed] = useState(false);
useEffect(() => {
async function check(): Promise<void> {
const talerUri = await findTalerUriInActiveTab();
- setTalerActionUrl(talerUri)
+ setTalerActionUrl(talerUri);
}
check();
}, []);
diff --git a/packages/taler-wallet-webextension/src/i18n/strings.ts b/packages/taler-wallet-webextension/src/i18n/strings.ts
index 5b1257830..0fefb0f70 100644
--- a/packages/taler-wallet-webextension/src/i18n/strings.ts
+++ b/packages/taler-wallet-webextension/src/i18n/strings.ts
@@ -193,7 +193,7 @@ strings["es"] = {
"Order redirected": [""],
"Payment aborted": [""],
"Payment Sent": [""],
- "Backup": ["Resguardo"],
+ Backup: ["Resguardo"],
"Order accepted": [""],
"Reserve balance updated": [""],
"Payment refund": [""],
diff --git a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx b/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
index d256f6d98..232b0da73 100644
--- a/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Backup.stories.tsx
@@ -15,179 +15,184 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { addDays } from 'date-fns';
-import { BackupView as TestedComponent } from './BackupPage';
-import { createExample } from '../test-utils';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { addDays } from "date-fns";
+import { BackupView as TestedComponent } from "./BackupPage";
+import { createExample } from "../test-utils";
export default {
- title: 'popup/backup/list',
+ title: "popup/backup/list",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const LotOfProviders = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": addDays(new Date(), 13).getTime()
- }
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: addDays(new Date(), 13).getTime(),
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
- newTerms: {
- annualFee: 'USD:2',
- storageLimitInMegabytes: 8,
- supportedProtocolVersion: '2',
- },
- oldTerms: {
- annualFee: 'USD:1',
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
+ newTerms: {
+ annualFee: "USD:2",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "2",
+ },
+ oldTerms: {
+ annualFee: "USD:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "1",
+ },
+ paidUntil: {
+ t_ms: "never",
+ },
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
storageLimitInMegabytes: 16,
- supportedProtocolVersion: '1',
-
+ supportedProtocolVersion: "0.0",
},
- paidUntil: {
- t_ms: 'never'
- }
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const OneProvider = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const Empty = createExample(TestedComponent, {
- providers: []
+ providers: [],
});
-
diff --git a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
index dcc5e5313..894c8a791 100644
--- a/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BackupPage.tsx
@@ -14,15 +14,28 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus } from "@gnu-taler/taler-wallet-core";
-import { differenceInMonths, formatDuration, intervalToDuration } from "date-fns";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+} from "@gnu-taler/taler-wallet-core";
+import {
+ differenceInMonths,
+ formatDuration,
+ intervalToDuration,
+} from "date-fns";
import { Fragment, JSX, VNode, h } from "preact";
import {
- BoldLight, ButtonPrimary, ButtonSuccess, Centered,
- CenteredText, CenteredBoldText, PopupBox, RowBorderGray,
- SmallText, SmallLightText
+ BoldLight,
+ ButtonPrimary,
+ ButtonSuccess,
+ Centered,
+ CenteredText,
+ CenteredBoldText,
+ PopupBox,
+ RowBorderGray,
+ SmallText,
+ SmallLightText,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "../NavigationBar";
@@ -32,49 +45,68 @@ interface Props {
}
export function BackupPage({ onAddProvider }: Props): VNode {
- const status = useBackupStatus()
+ const status = useBackupStatus();
if (!status) {
- return <div>Loading...</div>
+ return <div>Loading...</div>;
}
- return <BackupView providers={status.providers} onAddProvider={onAddProvider} onSyncAll={status.sync} />;
+ return (
+ <BackupView
+ providers={status.providers}
+ onAddProvider={onAddProvider}
+ onSyncAll={status.sync}
+ />
+ );
}
export interface ViewProps {
- providers: ProviderInfo[],
+ providers: ProviderInfo[];
onAddProvider: () => void;
onSyncAll: () => Promise<void>;
}
-export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps): VNode {
+export function BackupView({
+ providers,
+ onAddProvider,
+ onSyncAll,
+}: ViewProps): VNode {
return (
<PopupBox>
<section>
- {providers.map((provider) => <BackupLayout
- status={provider.paymentStatus}
- timestamp={provider.lastSuccessfulBackupTimestamp}
- id={provider.syncProviderBaseUrl}
- active={provider.active}
- title={provider.name}
- />
+ {providers.map((provider) => (
+ <BackupLayout
+ status={provider.paymentStatus}
+ timestamp={provider.lastSuccessfulBackupTimestamp}
+ id={provider.syncProviderBaseUrl}
+ active={provider.active}
+ title={provider.name}
+ />
+ ))}
+ {!providers.length && (
+ <Centered style={{ marginTop: 100 }}>
+ <BoldLight>No backup providers configured</BoldLight>
+ <ButtonSuccess onClick={onAddProvider}>
+ <i18n.Translate>Add provider</i18n.Translate>
+ </ButtonSuccess>
+ </Centered>
)}
- {!providers.length && <Centered style={{marginTop: 100}}>
- <BoldLight>No backup providers configured</BoldLight>
- <ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
- </Centered>}
</section>
- {!!providers.length && <footer>
- <div />
- <div>
- <ButtonPrimary onClick={onSyncAll}>{
- providers.length > 1 ?
- <i18n.Translate>Sync all backups</i18n.Translate> :
- <i18n.Translate>Sync now</i18n.Translate>
- }</ButtonPrimary>
- <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
- </div>
- </footer>}
+ {!!providers.length && (
+ <footer>
+ <div />
+ <div>
+ <ButtonPrimary onClick={onSyncAll}>
+ {providers.length > 1 ? (
+ <i18n.Translate>Sync all backups</i18n.Translate>
+ ) : (
+ <i18n.Translate>Sync now</i18n.Translate>
+ )}
+ </ButtonPrimary>
+ <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
+ </div>
+ </footer>
+ )}
</PopupBox>
- )
+ );
}
interface TransactionLayoutProps {
@@ -92,55 +124,73 @@ function BackupLayout(props: TransactionLayoutProps): JSX.Element {
timeStyle: "short",
} as any);
-
return (
<RowBorderGray>
<div style={{ color: !props.active ? "grey" : undefined }}>
- <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 && <SmallLightText style={{marginTop: 5}}>Not synced</SmallLightText>}
+ <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 && (
+ <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>
+ )}
</div>
<div>
- {props.status?.type === 'paid' ?
- <ExpirationText until={props.status.paidUntil} /> :
+ {props.status?.type === "paid" ? (
+ <ExpirationText until={props.status.paidUntil} />
+ ) : (
<div>{props.status.type}</div>
- }
+ )}
</div>
</RowBorderGray>
);
}
function ExpirationText({ until }: { until: Timestamp }) {
- return <Fragment>
- <CenteredText> Expires in </CenteredText>
- <CenteredBoldText {...({ color: colorByTimeToExpire(until) })}> {daysUntil(until)} </CenteredBoldText>
- </Fragment>
+ return (
+ <Fragment>
+ <CenteredText> Expires in </CenteredText>
+ <CenteredBoldText {...{ color: colorByTimeToExpire(until) }}>
+ {" "}
+ {daysUntil(until)}{" "}
+ </CenteredBoldText>
+ </Fragment>
+ );
}
function colorByTimeToExpire(d: Timestamp) {
- if (d.t_ms === 'never') return 'rgb(28, 184, 65)'
- const months = differenceInMonths(d.t_ms, new Date())
- return months > 1 ? 'rgb(28, 184, 65)' : 'rgb(223, 117, 20)';
+ if (d.t_ms === "never") return "rgb(28, 184, 65)";
+ const months = differenceInMonths(d.t_ms, new Date());
+ return months > 1 ? "rgb(28, 184, 65)" : "rgb(223, 117, 20)";
}
function daysUntil(d: Timestamp) {
- if (d.t_ms === 'never') return undefined
+ if (d.t_ms === "never") return undefined;
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? 'years' : (
- duration?.months ? 'months' : (
- duration?.days ? 'days' : (
- duration.hours ? 'hours' : 'minutes'
- )
- )
- )
- ]
- })
- return `${str}`
-} \ No newline at end of file
+ duration?.years
+ ? "years"
+ : duration?.months
+ ? "months"
+ : duration?.days
+ ? "days"
+ : duration.hours
+ ? "hours"
+ : "minutes",
+ ],
+ });
+ return `${str}`;
+}
diff --git a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
index 382f9b549..80203f6d3 100644
--- a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx
@@ -15,28 +15,25 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample, NullLink } from '../test-utils';
-import { BalanceView as TestedComponent } from './BalancePage';
+import { createExample, NullLink } from "../test-utils";
+import { BalanceView as TestedComponent } from "./BalancePage";
export default {
- title: 'popup/balance',
+ title: "popup/balance",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
-export const NotYetLoaded = createExample(TestedComponent, {
-});
+export const NotYetLoaded = createExample(TestedComponent, {});
export const GotError = createExample(TestedComponent, {
balance: {
hasError: true,
- message: 'Network error'
+ message: "Network error",
},
Linker: NullLink,
});
@@ -45,7 +42,7 @@ export const EmptyBalance = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: []
+ balances: [],
},
},
Linker: NullLink,
@@ -55,13 +52,15 @@ export const SomeCoins = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:10.5',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:10.5",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -71,13 +70,15 @@ export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2.23',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5.11',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2.23",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5.11",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -87,13 +88,15 @@ export const SomeCoinsAndOutgoingMoney = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2.23',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:5.11',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2.23",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:5.11",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -103,13 +106,15 @@ export const SomeCoinsAndMovingMoney = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2.23',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:2',
- pendingOutgoing: 'USD:5.11',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2.23",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:2",
+ pendingOutgoing: "USD:5.11",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -119,19 +124,22 @@ export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5.1',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'EUR:4',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:0',
- pendingOutgoing: 'EUR:3.01',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5.1",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "EUR:4",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:0",
+ pendingOutgoing: "EUR:3.01",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -141,78 +149,89 @@ export const SomeCoinsInTreeCurrencies = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:1',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'COL:2000',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'EUR:4',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:15',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:1",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "COL:2000",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "EUR:4",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:15",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
});
-
export const SomeCoinsInFiveCurrencies = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:13451',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'EUR:202.02',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:0',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- },{
- available: 'ARS:30',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'JPY:51223233',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:0',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- },{
- available: 'JPY:51223233',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:0',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- },{
- available: 'DEMOKUDOS:6',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'TESTKUDOS:6',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:13451",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "EUR:202.02",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:0",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "ARS:30",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "JPY:51223233",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:0",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "JPY:51223233",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:0",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "DEMOKUDOS:6",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "TESTKUDOS:6",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
index 8e5c5c42e..2913f60e0 100644
--- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx
@@ -15,20 +15,37 @@
*/
import {
- amountFractionalBase, Amounts,
- Balance, BalancesResponse,
- i18n
+ amountFractionalBase,
+ Amounts,
+ Balance,
+ BalancesResponse,
+ i18n,
} from "@gnu-taler/taler-util";
import { JSX, h, Fragment } from "preact";
import { ErrorMessage } from "../components/ErrorMessage";
-import { PopupBox, Centered, ButtonPrimary, ErrorBox, Middle } from "../components/styled/index";
+import {
+ PopupBox,
+ Centered,
+ ButtonPrimary,
+ ErrorBox,
+ Middle,
+} from "../components/styled/index";
import { BalancesHook, useBalances } from "../hooks/useBalances";
import { PageLink, renderAmount } from "../renderHtml";
-
-export function BalancePage({ goToWalletManualWithdraw }: { goToWalletManualWithdraw: () => void }) {
- const balance = useBalances()
- return <BalanceView balance={balance} Linker={PageLink} goToWalletManualWithdraw={goToWalletManualWithdraw} />
+export function BalancePage({
+ goToWalletManualWithdraw,
+}: {
+ goToWalletManualWithdraw: () => void;
+}) {
+ const balance = useBalances();
+ return (
+ <BalanceView
+ balance={balance}
+ Linker={PageLink}
+ goToWalletManualWithdraw={goToWalletManualWithdraw}
+ />
+ );
}
export interface BalanceViewProps {
balance: BalancesHook;
@@ -46,22 +63,26 @@ function formatPending(entry: Balance): JSX.Element {
if (!Amounts.isZero(pendingIncoming)) {
incoming = (
- <span><i18n.Translate>
- <span style={{ color: "darkgreen" }} title="incoming amount">
- {"+"}
- {renderAmount(entry.pendingIncoming)}
- </span>{" "}
- </i18n.Translate></span>
+ <span>
+ <i18n.Translate>
+ <span style={{ color: "darkgreen" }} title="incoming amount">
+ {"+"}
+ {renderAmount(entry.pendingIncoming)}
+ </span>{" "}
+ </i18n.Translate>
+ </span>
);
}
if (!Amounts.isZero(pendingOutgoing)) {
payment = (
- <span><i18n.Translate>
- <span style={{ color: "darkred" }} title="outgoing amount">
- {"-"}
- {renderAmount(entry.pendingOutgoing)}
- </span>{" "}
- </i18n.Translate></span>
+ <span>
+ <i18n.Translate>
+ <span style={{ color: "darkred" }} title="outgoing amount">
+ {"-"}
+ {renderAmount(entry.pendingOutgoing)}
+ </span>{" "}
+ </i18n.Translate>
+ </span>
);
}
@@ -80,76 +101,110 @@ function formatPending(entry: Balance): JSX.Element {
);
}
-
-export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) {
-
+export function BalanceView({
+ balance,
+ Linker,
+ goToWalletManualWithdraw,
+}: BalanceViewProps) {
function Content() {
if (!balance) {
- return <span />
+ return <span />;
}
if (balance.hasError) {
- return (<section>
- <ErrorBox>{balance.message}</ErrorBox>
- <p>
- Click <Linker pageName="welcome">here</Linker> for help and
- diagnostics.
- </p>
- </section>)
+ return (
+ <section>
+ <ErrorBox>{balance.message}</ErrorBox>
+ <p>
+ Click <Linker pageName="welcome">here</Linker> for help and
+ diagnostics.
+ </p>
+ </section>
+ );
}
if (balance.response.balances.length === 0) {
- return (<section data-expanded>
- <Middle>
- <p><i18n.Translate>
- You have no balance to show. Need some{" "}
- <Linker pageName="/welcome">help</Linker> getting started?
- </i18n.Translate></p>
- </Middle>
- </section>)
+ return (
+ <section data-expanded>
+ <Middle>
+ <p>
+ <i18n.Translate>
+ You have no balance to show. Need some{" "}
+ <Linker pageName="/welcome">help</Linker> getting started?
+ </i18n.Translate>
+ </p>
+ </Middle>
+ </section>
+ );
}
- return <section data-expanded data-centered>
- <table style={{width:'100%'}}>{balance.response.balances.map((entry) => {
- const av = Amounts.parseOrThrow(entry.available);
- // Create our number formatter.
- let formatter;
- try {
- formatter = new Intl.NumberFormat('en-US', {
- style: 'currency',
- currency: av.currency,
- currencyDisplay: 'symbol'
- // These options are needed to round to whole numbers if that's what you want.
- //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
- //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
- });
- } catch {
- formatter = new Intl.NumberFormat('en-US', {
- // style: 'currency',
- // currency: av.currency,
- // These options are needed to round to whole numbers if that's what you want.
- //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
- //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
- });
- }
-
- const v = formatter.format(av.value + av.fraction / amountFractionalBase);
- const fontSize = v.length < 8 ? '3em' : (v.length < 13 ? '2em' : '1em')
- return (<tr>
- <td style={{ height: 50, fontSize, width: '60%', textAlign: 'right', padding: 0 }}>{v}</td>
- <td style={{ maxWidth: '2em', overflowX: 'hidden' }}>{av.currency}</td>
- <td style={{ fontSize: 'small', color: 'gray' }}>{formatPending(entry)}</td>
- </tr>
- );
- })}</table>
- </section>
+ return (
+ <section data-expanded data-centered>
+ <table style={{ width: "100%" }}>
+ {balance.response.balances.map((entry) => {
+ const av = Amounts.parseOrThrow(entry.available);
+ // Create our number formatter.
+ let formatter;
+ try {
+ formatter = new Intl.NumberFormat("en-US", {
+ style: "currency",
+ currency: av.currency,
+ currencyDisplay: "symbol",
+ // These options are needed to round to whole numbers if that's what you want.
+ //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
+ //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
+ });
+ } catch {
+ formatter = new Intl.NumberFormat("en-US", {
+ // style: 'currency',
+ // currency: av.currency,
+ // These options are needed to round to whole numbers if that's what you want.
+ //minimumFractionDigits: 0, // (this suffices for whole numbers, but will print 2500.10 as $2,500.1)
+ //maximumFractionDigits: 0, // (causes 2500.99 to be printed as $2,501)
+ });
+ }
+
+ const v = formatter.format(
+ av.value + av.fraction / amountFractionalBase,
+ );
+ const fontSize =
+ v.length < 8 ? "3em" : v.length < 13 ? "2em" : "1em";
+ return (
+ <tr>
+ <td
+ style={{
+ height: 50,
+ fontSize,
+ width: "60%",
+ textAlign: "right",
+ padding: 0,
+ }}
+ >
+ {v}
+ </td>
+ <td style={{ maxWidth: "2em", overflowX: "hidden" }}>
+ {av.currency}
+ </td>
+ <td style={{ fontSize: "small", color: "gray" }}>
+ {formatPending(entry)}
+ </td>
+ </tr>
+ );
+ })}
+ </table>
+ </section>
+ );
}
- return <PopupBox>
- {/* <section> */}
- <Content />
- {/* </section> */}
- <footer>
- <div />
- <ButtonPrimary onClick={goToWalletManualWithdraw}>Withdraw</ButtonPrimary>
- </footer>
- </PopupBox>
+ return (
+ <PopupBox>
+ {/* <section> */}
+ <Content />
+ {/* </section> */}
+ <footer>
+ <div />
+ <ButtonPrimary onClick={goToWalletManualWithdraw}>
+ Withdraw
+ </ButtonPrimary>
+ </footer>
+ </PopupBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/popup/Debug.tsx b/packages/taler-wallet-webextension/src/popup/Debug.tsx
index ccc747466..8722c1cf8 100644
--- a/packages/taler-wallet-webextension/src/popup/Debug.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Debug.tsx
@@ -19,13 +19,14 @@ import { Diagnostics } from "../components/Diagnostics";
import { useDiagnostics } from "../hooks/useDiagnostics.js";
import * as wxApi from "../wxApi";
-
export function DeveloperPage(props: any): JSX.Element {
const [status, timedOut] = useDiagnostics();
return (
<div>
<p>Debug tools:</p>
- <button onClick={openExtensionPage("/static/popup.html")}>wallet tab</button>
+ <button onClick={openExtensionPage("/static/popup.html")}>
+ wallet tab
+ </button>
<br />
<button onClick={confirmReset}>reset</button>
<Diagnostics diagnostics={status} timedOut={timedOut} />
@@ -46,7 +47,7 @@ export async function confirmReset(): Promise<void> {
if (
confirm(
"Do you want to IRREVOCABLY DESTROY everything inside your" +
- " wallet and LOSE ALL YOUR COINS?",
+ " wallet and LOSE ALL YOUR COINS?",
)
) {
await wxApi.resetDb();
@@ -61,4 +62,3 @@ export function openExtensionPage(page: string) {
});
};
}
-
diff --git a/packages/taler-wallet-webextension/src/popup/History.stories.tsx b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
index daa263a81..95f4a547a 100644
--- a/packages/taler-wallet-webextension/src/popup/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.stories.tsx
@@ -15,135 +15,149 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import {
PaymentStatus,
- TransactionCommon, TransactionDeposit, TransactionPayment,
- TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+ TransactionCommon,
+ TransactionDeposit,
+ TransactionPayment,
+ TransactionRefresh,
+ TransactionRefund,
+ TransactionTip,
+ TransactionType,
TransactionWithdrawal,
- WithdrawalType
-} from '@gnu-taler/taler-util';
-import { createExample } from '../test-utils';
-import { HistoryView as TestedComponent } from './History';
+ WithdrawalType,
+} from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils";
+import { HistoryView as TestedComponent } from "./History";
export default {
- title: 'popup/history/list',
+ title: "popup/history/list",
component: TestedComponent,
};
const commonTransaction = {
- amountRaw: 'USD:10',
- amountEffective: 'USD:9',
+ amountRaw: "USD:10",
+ amountEffective: "USD:9",
pending: false,
timestamp: {
- t_ms: new Date().getTime()
+ t_ms: new Date().getTime(),
},
- transactionId: '12',
-} as TransactionCommon
+ transactionId: "12",
+} as TransactionCommon;
const exampleData = {
withdraw: {
...commonTransaction,
type: TransactionType.Withdrawal,
- exchangeBaseUrl: 'http://exchange.demo.taler.net',
+ exchangeBaseUrl: "http://exchange.demo.taler.net",
withdrawalDetails: {
confirmed: false,
- exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+ exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
- }
+ },
} as TransactionWithdrawal,
payment: {
...commonTransaction,
- amountEffective: 'USD:11',
+ amountEffective: "USD:11",
type: TransactionType.Payment,
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
- proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
deposit: {
...commonTransaction,
type: TransactionType.Deposit,
- depositGroupId: '#groupId',
- targetPaytoUri: 'payto://x-taler-bank/bank/account',
+ depositGroupId: "#groupId",
+ targetPaytoUri: "payto://x-taler-bank/bank/account",
} as TransactionDeposit,
refresh: {
...commonTransaction,
type: TransactionType.Refresh,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
} as TransactionRefresh,
tip: {
...commonTransaction,
type: TransactionType.Tip,
- merchantBaseUrl: 'http://merchant.taler',
+ merchantBaseUrl: "http://merchant.taler",
} as TransactionTip,
refund: {
...commonTransaction,
type: TransactionType.Refund,
- refundedTransactionId: 'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ refundedTransactionId:
+ "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
} as TransactionRefund,
-}
+};
export const EmptyWithBalance = createExample(TestedComponent, {
list: [],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const EmptyWithNoBalance = createExample(TestedComponent, {
list: [],
- balances: []
+ balances: [],
});
export const One = createExample(TestedComponent, {
list: [exampleData.withdraw],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const OnePending = createExample(TestedComponent, {
- list: [{
- ...exampleData.withdraw,
- pending: true,
- }],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ list: [
+ {
+ ...exampleData.withdraw,
+ pending: true,
+ },
+ ],
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const Several = createExample(TestedComponent, {
@@ -157,13 +171,15 @@ export const Several = createExample(TestedComponent, {
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
@@ -177,18 +193,20 @@ export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }, {
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
-
diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx b/packages/taler-wallet-webextension/src/popup/History.tsx
index 1447da9b0..8fe6de16c 100644
--- a/packages/taler-wallet-webextension/src/popup/History.tsx
+++ b/packages/taler-wallet-webextension/src/popup/History.tsx
@@ -14,7 +14,13 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountString, Balance, i18n, Transaction, TransactionsResponse } from "@gnu-taler/taler-util";
+import {
+ AmountString,
+ Balance,
+ i18n,
+ Transaction,
+ TransactionsResponse,
+} from "@gnu-taler/taler-util";
import { h, JSX } from "preact";
import { useEffect, useState } from "preact/hooks";
import { PopupBox } from "../components/styled";
@@ -22,13 +28,14 @@ import { TransactionItem } from "../components/TransactionItem";
import { useBalances } from "../hooks/useBalances";
import * as wxApi from "../wxApi";
-
export function HistoryPage(props: any): JSX.Element {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
- const balance = useBalances()
- const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || [])
+ const balance = useBalances();
+ const balanceWithoutError = balance?.hasError
+ ? []
+ : balance?.response.balances || [];
useEffect(() => {
const fetchData = async (): Promise<void> => {
@@ -42,46 +49,79 @@ export function HistoryPage(props: any): JSX.Element {
return <div>Loading ...</div>;
}
- return <HistoryView balances={balanceWithoutError} list={[...transactions.transactions].reverse()} />;
+ return (
+ <HistoryView
+ balances={balanceWithoutError}
+ list={[...transactions.transactions].reverse()}
+ />
+ );
}
function amountToString(c: AmountString) {
- const idx = c.indexOf(':')
- return `${c.substring(idx + 1)} ${c.substring(0, idx)}`
+ const idx = c.indexOf(":");
+ return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
}
-
-
-export function HistoryView({ list, balances }: { list: Transaction[], balances: Balance[] }) {
- const multiCurrency = balances.length > 1
- return <PopupBox noPadding>
- {balances.length > 0 && <header>
- {multiCurrency ? <div class="title">
- Balance: <ul style={{ margin: 0 }}>
- {balances.map(b => <li>{b.available}</li>)}
- </ul>
- </div> : <div class="title">
- Balance: <span>{amountToString(balances[0].available)}</span>
- </div>}
- </header>}
- {list.length === 0 ? <section data-expanded data-centered>
- <p><i18n.Translate>
- You have no history yet, here you will be able to check your last transactions.
- </i18n.Translate></p>
- </section> :
- <section>
- {list.slice(0, 3).map((tx, i) => (
- <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency} />
- ))}
- </section>
- }
- <footer style={{ justifyContent: 'space-around' }}>
- {list.length > 0 &&
- <a target="_blank"
- rel="noopener noreferrer"
- style={{ color: 'darkgreen', textDecoration: 'none' }}
- href={chrome.extension ? chrome.extension.getURL(`/static/wallet.html#/history`) : '#'}>VIEW MORE TRANSACTIONS</a>
- }
- </footer>
- </PopupBox>
+export function HistoryView({
+ list,
+ balances,
+}: {
+ list: Transaction[];
+ balances: Balance[];
+}) {
+ const multiCurrency = balances.length > 1;
+ return (
+ <PopupBox noPadding>
+ {balances.length > 0 && (
+ <header>
+ {multiCurrency ? (
+ <div class="title">
+ Balance:{" "}
+ <ul style={{ margin: 0 }}>
+ {balances.map((b) => (
+ <li>{b.available}</li>
+ ))}
+ </ul>
+ </div>
+ ) : (
+ <div class="title">
+ Balance: <span>{amountToString(balances[0].available)}</span>
+ </div>
+ )}
+ </header>
+ )}
+ {list.length === 0 ? (
+ <section data-expanded data-centered>
+ <p>
+ <i18n.Translate>
+ You have no history yet, here you will be able to check your last
+ transactions.
+ </i18n.Translate>
+ </p>
+ </section>
+ ) : (
+ <section>
+ {list.slice(0, 3).map((tx, i) => (
+ <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency} />
+ ))}
+ </section>
+ )}
+ <footer style={{ justifyContent: "space-around" }}>
+ {list.length > 0 && (
+ <a
+ target="_blank"
+ rel="noopener noreferrer"
+ style={{ color: "darkgreen", textDecoration: "none" }}
+ href={
+ chrome.extension
+ ? chrome.extension.getURL(`/static/wallet.html#/history`)
+ : "#"
+ }
+ >
+ VIEW MORE TRANSACTIONS
+ </a>
+ )}
+ </footer>
+ </PopupBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/popup/Popup.stories.tsx b/packages/taler-wallet-webextension/src/popup/Popup.stories.tsx
index cd443e9d4..5009684c5 100644
--- a/packages/taler-wallet-webextension/src/popup/Popup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Popup.stories.tsx
@@ -15,30 +15,29 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { NavBar as TestedComponent } from '../NavigationBar';
+import { createExample } from "../test-utils";
+import { NavBar as TestedComponent } from "../NavigationBar";
export default {
- title: 'popup/header',
+ title: "popup/header",
// component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const OnBalance = createExample(TestedComponent, {
- devMode:false,
- path:'/balance'
+ devMode: false,
+ path: "/balance",
});
export const OnHistoryWithDevMode = createExample(TestedComponent, {
- devMode:true,
- path:'/history'
+ devMode: true,
+ path: "/history",
});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
index de1f67b96..0cff7f75f 100644
--- a/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/ProviderAddConfirmProvider.stories.tsx
@@ -15,38 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { ConfirmProviderView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { ConfirmProviderView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'popup/backup/confirm',
+ title: "popup/backup/confirm",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const DemoService = createExample(TestedComponent, {
- url: 'https://sync.demo.taler.net/',
+ url: "https://sync.demo.taler.net/",
provider: {
- annual_fee: 'KUDOS:0.1',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "KUDOS:0.1",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
export const FreeService = createExample(TestedComponent, {
- url: 'https://sync.taler:9667/',
+ url: "https://sync.taler:9667/",
provider: {
- annual_fee: 'ARS:0',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "ARS:0",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
index 2daf49e0c..9a2f97051 100644
--- a/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/ProviderAddSetUrl.stories.tsx
@@ -15,39 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SetUrlView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { SetUrlView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'popup/backup/add',
+ title: "popup/backup/add",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
-export const Initial = createExample(TestedComponent, {
-});
+export const Initial = createExample(TestedComponent, {});
export const WithValue = createExample(TestedComponent, {
- initialValue: 'sync.demo.taler.net'
-});
+ initialValue: "sync.demo.taler.net",
+});
export const WithConnectionError = createExample(TestedComponent, {
- withError: 'Network error'
-});
+ withError: "Network error",
+});
export const WithClientError = createExample(TestedComponent, {
- withError: 'URL may not be right: (404) Not Found'
-});
+ withError: "URL may not be right: (404) Not Found",
+});
export const WithServerError = createExample(TestedComponent, {
- withError: 'Try another server: (500) Internal Server Error'
-});
+ withError: "Try another server: (500) Internal Server Error",
+});
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx b/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
index 4416608f8..fab21398a 100644
--- a/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/ProviderDetail.stories.tsx
@@ -15,224 +15,221 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { createExample } from '../test-utils';
-import { ProviderView as TestedComponent } from './ProviderDetailPage';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { createExample } from "../test-utils";
+import { ProviderView as TestedComponent } from "./ProviderDetailPage";
export default {
- title: 'popup/backup/details',
+ title: "popup/backup/details",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const Active = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveErrorSync = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
},
lastAttemptedBackupTimestamp: {
- "t_ms": 1625063925078
+ t_ms: 1625063925078,
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
lastError: {
code: 2002,
- details: 'details',
- hint: 'error hint from the server',
- message: 'message'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ details: "details",
+ hint: "error hint from the server",
+ message: "message",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemUnreadable = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-unreadable'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ type: "backup-unreadable",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemDevice = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-conflicting-device',
- myDeviceId: 'my-device-id',
- otherDeviceId: 'other-device-id',
+ type: "backup-conflicting-device",
+ myDeviceId: "my-device-id",
+ otherDeviceId: "other-device-id",
backupTimestamp: {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveUnpaid = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveInsufficientBalance = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactivePending = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
export const ActiveTermsChanged = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
paidUntil: {
- t_ms: 1656599921000
+ t_ms: 1656599921000,
},
newTerms: {
- "annualFee": "EUR:10",
- "storageLimitInMegabytes": 8,
- "supportedProtocolVersion": "0.0"
+ annualFee: "EUR:10",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "0.0",
},
oldTerms: {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
diff --git a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
index 04adbb21c..9617c9a41 100644
--- a/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/popup/ProviderDetailPage.tsx
@@ -14,13 +14,23 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+ ProviderPaymentType,
+} from "@gnu-taler/taler-wallet-core";
import { format, formatDuration, intervalToDuration } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { ErrorMessage } from "../components/ErrorMessage";
-import { Button, ButtonDestructive, ButtonPrimary, PaymentStatus, PopupBox, SmallLightText } from "../components/styled";
+import {
+ Button,
+ ButtonDestructive,
+ ButtonPrimary,
+ PaymentStatus,
+ PopupBox,
+ SmallLightText,
+} from "../components/styled";
import { useProviderStatus } from "../hooks/useProviderStatus";
interface Props {
@@ -29,20 +39,29 @@ interface Props {
}
export function ProviderDetailPage({ pid, onBack }: Props): VNode {
- const status = useProviderStatus(pid)
+ const status = useProviderStatus(pid);
if (!status) {
- return <div><i18n.Translate>Loading...</i18n.Translate></div>
+ return (
+ <div>
+ <i18n.Translate>Loading...</i18n.Translate>
+ </div>
+ );
}
if (!status.info) {
- onBack()
- return <div />
+ onBack();
+ return <div />;
}
- return <ProviderView info={status.info}
- onSync={status.sync}
- onDelete={() => status.remove().then(onBack)}
- onBack={onBack}
- onExtend={() => { null }}
- />;
+ return (
+ <ProviderView
+ info={status.info}
+ onSync={status.sync}
+ onDelete={() => status.remove().then(onBack)}
+ onBack={onBack}
+ onExtend={() => {
+ null;
+ }}
+ />
+ );
}
export interface ViewProps {
@@ -53,124 +72,185 @@ export interface ViewProps {
onExtend: () => void;
}
-export function ProviderView({ info, onDelete, onSync, onBack, onExtend }: ViewProps): VNode {
- const lb = info?.lastSuccessfulBackupTimestamp
- const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || info.paymentStatus.type === ProviderPaymentType.TermsChanged
+export function ProviderView({
+ info,
+ onDelete,
+ onSync,
+ onBack,
+ onExtend,
+}: ViewProps): VNode {
+ const lb = info?.lastSuccessfulBackupTimestamp;
+ const isPaid =
+ info.paymentStatus.type === ProviderPaymentType.Paid ||
+ info.paymentStatus.type === ProviderPaymentType.TermsChanged;
return (
<PopupBox>
<Error info={info} />
<header>
- <h3>{info.name} <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText></h3>
- <PaymentStatus color={isPaid ? 'rgb(28, 184, 65)' : 'rgb(202, 60, 60)'}>{isPaid ? 'Paid' : 'Unpaid'}</PaymentStatus>
+ <h3>
+ {info.name}{" "}
+ <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText>
+ </h3>
+ <PaymentStatus color={isPaid ? "rgb(28, 184, 65)" : "rgb(202, 60, 60)"}>
+ {isPaid ? "Paid" : "Unpaid"}
+ </PaymentStatus>
</header>
<section>
- <p><b>Last backup:</b> {lb == null || lb.t_ms == "never" ? "never" : format(lb.t_ms, 'dd MMM yyyy')} </p>
- <ButtonPrimary onClick={onSync}><i18n.Translate>Back up</i18n.Translate></ButtonPrimary>
- {info.terms && <Fragment>
- <p><b>Provider fee:</b> {info.terms && info.terms.annualFee} per year</p>
- </Fragment>
- }
+ <p>
+ <b>Last backup:</b>{" "}
+ {lb == null || lb.t_ms == "never"
+ ? "never"
+ : format(lb.t_ms, "dd MMM yyyy")}{" "}
+ </p>
+ <ButtonPrimary onClick={onSync}>
+ <i18n.Translate>Back up</i18n.Translate>
+ </ButtonPrimary>
+ {info.terms && (
+ <Fragment>
+ <p>
+ <b>Provider fee:</b> {info.terms && info.terms.annualFee} per year
+ </p>
+ </Fragment>
+ )}
<p>{descriptionByStatus(info.paymentStatus)}</p>
- <ButtonPrimary disabled onClick={onExtend}><i18n.Translate>Extend</i18n.Translate></ButtonPrimary>
-
- {info.paymentStatus.type === ProviderPaymentType.TermsChanged && <div>
- <p><i18n.Translate>terms has changed, extending the service will imply accepting the new terms of service</i18n.Translate></p>
- <table>
- <thead>
- <tr>
- <td></td>
- <td><i18n.Translate>old</i18n.Translate></td>
- <td> -&gt;</td>
- <td><i18n.Translate>new</i18n.Translate></td>
- </tr>
- </thead>
- <tbody>
-
- <tr>
- <td><i18n.Translate>fee</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.annualFee}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.annualFee}</td>
- </tr>
- <tr>
- <td><i18n.Translate>storage</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
- </tr>
- </tbody>
- </table>
- </div>}
+ <ButtonPrimary disabled onClick={onExtend}>
+ <i18n.Translate>Extend</i18n.Translate>
+ </ButtonPrimary>
+ {info.paymentStatus.type === ProviderPaymentType.TermsChanged && (
+ <div>
+ <p>
+ <i18n.Translate>
+ terms has changed, extending the service will imply accepting
+ the new terms of service
+ </i18n.Translate>
+ </p>
+ <table>
+ <thead>
+ <tr>
+ <td></td>
+ <td>
+ <i18n.Translate>old</i18n.Translate>
+ </td>
+ <td> -&gt;</td>
+ <td>
+ <i18n.Translate>new</i18n.Translate>
+ </td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <i18n.Translate>fee</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.annualFee}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.annualFee}</td>
+ </tr>
+ <tr>
+ <td>
+ <i18n.Translate>storage</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ )}
</section>
<footer>
- <Button onClick={onBack}><i18n.Translate> &lt; back</i18n.Translate></Button>
+ <Button onClick={onBack}>
+ <i18n.Translate> &lt; back</i18n.Translate>
+ </Button>
<div>
- <ButtonDestructive onClick={onDelete}><i18n.Translate>remove provider</i18n.Translate></ButtonDestructive>
+ <ButtonDestructive onClick={onDelete}>
+ <i18n.Translate>remove provider</i18n.Translate>
+ </ButtonDestructive>
</div>
</footer>
</PopupBox>
- )
+ );
}
function daysSince(d?: Timestamp) {
- if (!d || d.t_ms === 'never') return 'never synced'
+ if (!d || d.t_ms === "never") return "never synced";
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? i18n.str`years` : (
- duration?.months ? i18n.str`months` : (
- duration?.days ? i18n.str`days` : (
- duration?.hours ? i18n.str`hours` : (
- duration?.minutes ? i18n.str`minutes` : i18n.str`seconds`
- )
- )
- )
- )
- ]
- })
- return `synced ${str} ago`
+ duration?.years
+ ? i18n.str`years`
+ : duration?.months
+ ? i18n.str`months`
+ : duration?.days
+ ? i18n.str`days`
+ : duration?.hours
+ ? i18n.str`hours`
+ : duration?.minutes
+ ? i18n.str`minutes`
+ : i18n.str`seconds`,
+ ],
+ });
+ return `synced ${str} ago`;
}
function Error({ info }: { info: ProviderInfo }) {
if (info.lastError) {
- return <ErrorMessage title={info.lastError.hint} />
+ return <ErrorMessage title={info.lastError.hint} />;
}
if (info.backupProblem) {
switch (info.backupProblem.type) {
case "backup-conflicting-device":
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>There is conflict with another backup from <b>{info.backupProblem.otherDeviceId}</b></i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ There is conflict with another backup from{" "}
+ <b>{info.backupProblem.otherDeviceId}</b>
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
case "backup-unreadable":
- return <ErrorMessage title="Backup is not readable" />
+ return <ErrorMessage title="Backup is not readable" />;
default:
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>Unknown backup problem: {JSON.stringify(info.backupProblem)}</i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ Unknown backup problem: {JSON.stringify(info.backupProblem)}
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
}
}
- return null
+ return null;
}
function colorByStatus(status: ProviderPaymentType) {
switch (status) {
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(223, 117, 20)'
+ return "rgb(223, 117, 20)";
case ProviderPaymentType.Unpaid:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.Paid:
- return 'rgb(28, 184, 65)'
+ return "rgb(28, 184, 65)";
case ProviderPaymentType.Pending:
- return 'gray'
+ return "gray";
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.TermsChanged:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
}
}
@@ -180,16 +260,19 @@ function descriptionByStatus(status: ProviderPaymentStatus) {
// return i18n.str`not paid yet`
case ProviderPaymentType.Paid:
case ProviderPaymentType.TermsChanged:
- if (status.paidUntil.t_ms === 'never') {
- return i18n.str`service paid`
+ if (status.paidUntil.t_ms === "never") {
+ return i18n.str`service paid`;
} else {
- return <Fragment>
- <b>Backup valid until:</b> {format(status.paidUntil.t_ms, 'dd MMM yyyy')}
- </Fragment>
+ return (
+ <Fragment>
+ <b>Backup valid until:</b>{" "}
+ {format(status.paidUntil.t_ms, "dd MMM yyyy")}
+ </Fragment>
+ );
}
case ProviderPaymentType.Unpaid:
case ProviderPaymentType.InsufficientBalance:
case ProviderPaymentType.Pending:
- return ''
+ return "";
}
}
diff --git a/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx b/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx
index 06e33c9d3..ae8e54ba1 100644
--- a/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Settings.stories.tsx
@@ -15,29 +15,28 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SettingsView as TestedComponent } from './Settings';
+import { createExample } from "../test-utils";
+import { SettingsView as TestedComponent } from "./Settings";
export default {
- title: 'popup/settings',
+ title: "popup/settings",
component: TestedComponent,
argTypes: {
setDeviceName: () => Promise.resolve(),
- }
+ },
};
export const AllOff = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
setDeviceName: () => Promise.resolve(),
});
export const OneChecked = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
permissionsEnabled: true,
setDeviceName: () => Promise.resolve(),
});
-
diff --git a/packages/taler-wallet-webextension/src/popup/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx
index 8595c87ff..3b83f0762 100644
--- a/packages/taler-wallet-webextension/src/popup/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx
@@ -14,7 +14,6 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n } from "@gnu-taler/taler-util";
import { VNode, h } from "preact";
import { Checkbox } from "../components/Checkbox";
@@ -28,15 +27,21 @@ import { useLang } from "../hooks/useLang";
export function SettingsPage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
- const { devMode, toggleDevMode } = useDevContext()
- const { name, update } = useBackupDeviceName()
- const [lang, changeLang] = useLang()
- return <SettingsView
- lang={lang} changeLang={changeLang}
- deviceName={name} setDeviceName={update}
- permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
- developerMode={devMode} toggleDeveloperMode={toggleDevMode}
- />;
+ const { devMode, toggleDevMode } = useDevContext();
+ const { name, update } = useBackupDeviceName();
+ const [lang, changeLang] = useLang();
+ return (
+ <SettingsView
+ lang={lang}
+ changeLang={changeLang}
+ deviceName={name}
+ setDeviceName={update}
+ permissionsEnabled={permissionsEnabled}
+ togglePermissions={togglePermissions}
+ developerMode={devMode}
+ toggleDeveloperMode={toggleDevMode}
+ />
+ );
}
export interface ViewProps {
@@ -50,23 +55,31 @@ export interface ViewProps {
toggleDeveloperMode: () => void;
}
-import { strings as messages } from '../i18n/strings'
+import { strings as messages } from "../i18n/strings";
type LangsNames = {
- [P in keyof typeof messages]: string
-}
+ [P in keyof typeof messages]: string;
+};
const names: LangsNames = {
- es: 'Español [es]',
- en: 'English [en]',
- fr: 'Français [fr]',
- de: 'Deutsch [de]',
- sv: 'Svenska [sv]',
- it: 'Italiano [it]',
-}
-
+ es: "Español [es]",
+ en: "English [en]",
+ fr: "Français [fr]",
+ de: "Deutsch [de]",
+ sv: "Svenska [sv]",
+ it: "Italiano [it]",
+};
-export function SettingsView({ lang, changeLang, deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode {
+export function SettingsView({
+ lang,
+ changeLang,
+ deviceName,
+ setDeviceName,
+ permissionsEnabled,
+ togglePermissions,
+ developerMode,
+ toggleDeveloperMode,
+}: ViewProps): VNode {
return (
<PopupBox>
<section>
@@ -86,25 +99,39 @@ export function SettingsView({ lang, changeLang, deviceName, setDeviceName, perm
label={i18n.str`Device name`}
description="(This is how you will recognize the wallet in the backup provider)"
/> */}
- <h2><i18n.Translate>Permissions</i18n.Translate></h2>
- <Checkbox label="Automatically open wallet based on page content"
+ <h2>
+ <i18n.Translate>Permissions</i18n.Translate>
+ </h2>
+ <Checkbox
+ label="Automatically open wallet based on page content"
name="perm"
description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
- enabled={permissionsEnabled} onToggle={togglePermissions}
+ enabled={permissionsEnabled}
+ onToggle={togglePermissions}
/>
<h2>Config</h2>
- <Checkbox label="Developer mode"
+ <Checkbox
+ label="Developer mode"
name="devMode"
description="(More options and information useful for debugging)"
- enabled={developerMode} onToggle={toggleDeveloperMode}
+ enabled={developerMode}
+ onToggle={toggleDeveloperMode}
/>
</section>
- <footer style={{ justifyContent: 'space-around' }}>
- <a target="_blank"
+ <footer style={{ justifyContent: "space-around" }}>
+ <a
+ target="_blank"
rel="noopener noreferrer"
- style={{ color: 'darkgreen', textDecoration: 'none' }}
- href={chrome.extension ? chrome.extension.getURL(`/static/wallet.html#/settings`) : '#'}>VIEW MORE SETTINGS</a>
+ style={{ color: "darkgreen", textDecoration: "none" }}
+ href={
+ chrome.extension
+ ? chrome.extension.getURL(`/static/wallet.html#/settings`)
+ : "#"
+ }
+ >
+ VIEW MORE SETTINGS
+ </a>
</footer>
</PopupBox>
- )
-} \ No newline at end of file
+ );
+}
diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.stories.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.stories.tsx
index 88c7c725e..f20403d6a 100644
--- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.stories.tsx
+++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.stories.tsx
@@ -15,38 +15,38 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { TalerActionFound as TestedComponent } from './TalerActionFound';
+import { createExample } from "../test-utils";
+import { TalerActionFound as TestedComponent } from "./TalerActionFound";
export default {
- title: 'popup/TalerActionFound',
+ title: "popup/TalerActionFound",
component: TestedComponent,
};
export const PayAction = createExample(TestedComponent, {
- url: 'taler://pay/something'
+ url: "taler://pay/something",
});
export const WithdrawalAction = createExample(TestedComponent, {
- url: 'taler://withdraw/something'
+ url: "taler://withdraw/something",
});
export const TipAction = createExample(TestedComponent, {
- url: 'taler://tip/something'
+ url: "taler://tip/something",
});
export const NotifyAction = createExample(TestedComponent, {
- url: 'taler://notify-reserve/something'
+ url: "taler://notify-reserve/something",
});
export const RefundAction = createExample(TestedComponent, {
- url: 'taler://refund/something'
+ url: "taler://refund/something",
});
export const InvalidAction = createExample(TestedComponent, {
- url: 'taler://something/asd'
+ url: "taler://something/asd",
});
diff --git a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
index ef0ec341c..cbdcbeb15 100644
--- a/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
+++ b/packages/taler-wallet-webextension/src/popup/TalerActionFound.tsx
@@ -1,5 +1,31 @@
+/*
+ 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 { classifyTalerUri, TalerUriType } from "@gnu-taler/taler-util";
-import { ButtonPrimary, ButtonSuccess, PopupBox } from "../components/styled/index";
+import {
+ ButtonPrimary,
+ ButtonSuccess,
+ PopupBox,
+} from "../components/styled/index";
+import { h } from "preact";
export interface Props {
url: string;
@@ -8,54 +34,89 @@ export interface Props {
export function TalerActionFound({ url, onDismiss }: Props) {
const uriType = classifyTalerUri(url);
- return <PopupBox>
- <section>
- <h1>Taler Action </h1>
- {uriType === TalerUriType.TalerPay && <div>
- <p>This page has pay action.</p>
- <ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
- Open pay page
- </ButtonSuccess>
- </div>}
- {uriType === TalerUriType.TalerWithdraw && <div>
- <p>This page has a withdrawal action.</p>
- <ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
- Open withdraw page
- </ButtonSuccess>
- </div>}
- {uriType === TalerUriType.TalerTip && <div>
- <p>This page has a tip action.</p>
- <ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
- Open tip page
- </ButtonSuccess>
- </div>}
- {uriType === TalerUriType.TalerNotifyReserve && <div>
- <p>This page has a notify reserve action.</p>
- <ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
- Notify
- </ButtonSuccess>
- </div>}
- {uriType === TalerUriType.TalerRefund && <div>
- <p>This page has a refund action.</p>
- <ButtonSuccess onClick={() => { chrome.tabs.create({ "url": actionForTalerUri(uriType, url) }); }}>
- Open refund page
- </ButtonSuccess>
- </div>}
- {uriType === TalerUriType.Unknown && <div>
- <p>This page has a malformed taler uri.</p>
- <p>{url}</p>
- </div>}
-
- </section>
- <footer>
- <div />
- <ButtonPrimary onClick={() => onDismiss()}> Dismiss </ButtonPrimary>
- </footer>
- </PopupBox>;
-
+ return (
+ <PopupBox>
+ <section>
+ <h1>Taler Action </h1>
+ {uriType === TalerUriType.TalerPay && (
+ <div>
+ <p>This page has pay action.</p>
+ <ButtonSuccess
+ onClick={() => {
+ chrome.tabs.create({ url: actionForTalerUri(uriType, url) });
+ }}
+ >
+ Open pay page
+ </ButtonSuccess>
+ </div>
+ )}
+ {uriType === TalerUriType.TalerWithdraw && (
+ <div>
+ <p>This page has a withdrawal action.</p>
+ <ButtonSuccess
+ onClick={() => {
+ chrome.tabs.create({ url: actionForTalerUri(uriType, url) });
+ }}
+ >
+ Open withdraw page
+ </ButtonSuccess>
+ </div>
+ )}
+ {uriType === TalerUriType.TalerTip && (
+ <div>
+ <p>This page has a tip action.</p>
+ <ButtonSuccess
+ onClick={() => {
+ chrome.tabs.create({ url: actionForTalerUri(uriType, url) });
+ }}
+ >
+ Open tip page
+ </ButtonSuccess>
+ </div>
+ )}
+ {uriType === TalerUriType.TalerNotifyReserve && (
+ <div>
+ <p>This page has a notify reserve action.</p>
+ <ButtonSuccess
+ onClick={() => {
+ chrome.tabs.create({ url: actionForTalerUri(uriType, url) });
+ }}
+ >
+ Notify
+ </ButtonSuccess>
+ </div>
+ )}
+ {uriType === TalerUriType.TalerRefund && (
+ <div>
+ <p>This page has a refund action.</p>
+ <ButtonSuccess
+ onClick={() => {
+ chrome.tabs.create({ url: actionForTalerUri(uriType, url) });
+ }}
+ >
+ Open refund page
+ </ButtonSuccess>
+ </div>
+ )}
+ {uriType === TalerUriType.Unknown && (
+ <div>
+ <p>This page has a malformed taler uri.</p>
+ <p>{url}</p>
+ </div>
+ )}
+ </section>
+ <footer>
+ <div />
+ <ButtonPrimary onClick={() => onDismiss()}> Dismiss </ButtonPrimary>
+ </footer>
+ </PopupBox>
+ );
}
-function actionForTalerUri(uriType: TalerUriType, talerUri: string): string | undefined {
+function actionForTalerUri(
+ uriType: TalerUriType,
+ talerUri: string,
+): string | undefined {
switch (uriType) {
case TalerUriType.TalerWithdraw:
return makeExtensionUrlWithParams("static/wallet.html#/withdraw", {
@@ -91,8 +152,10 @@ function makeExtensionUrlWithParams(
): string {
const innerUrl = new URL(chrome.extension.getURL("/" + url));
if (params) {
- const hParams = Object.keys(params).map(k => `${k}=${params[k]}`).join('&')
- innerUrl.hash = innerUrl.hash + '?' + hParams
+ const hParams = Object.keys(params)
+ .map((k) => `${k}=${params[k]}`)
+ .join("&");
+ innerUrl.hash = innerUrl.hash + "?" + hParams;
}
return innerUrl.href;
}
diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
index 070df554c..a5723ccb5 100644
--- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx
@@ -22,19 +22,17 @@
import { setupI18n } from "@gnu-taler/taler-util";
import { createHashHistory } from "history";
-import { render, h, VNode } from "preact";
-import Router, { route, Route, getCurrentUrl } from "preact-router";
-import { useEffect, useState } from "preact/hooks";
+import { render, h } from "preact";
+import Router, { route, Route } from "preact-router";
+import { useEffect } from "preact/hooks";
import { DevContextProvider } from "./context/devContext";
import { useTalerActionURL } from "./hooks/useTalerActionURL";
import { strings } from "./i18n/strings";
+import { Pages, WalletNavBar } from "./NavigationBar";
import { BackupPage } from "./popup/BackupPage";
import { BalancePage } from "./popup/BalancePage";
-import { DeveloperPage as DeveloperPage } from "./popup/Debug";
+import { DeveloperPage } from "./popup/Debug";
import { HistoryPage } from "./popup/History";
-import {
- Pages, WalletNavBar
-} from "./NavigationBar";
import { ProviderAddPage } from "./popup/ProviderAddPage";
import { ProviderDetailPage } from "./popup/ProviderDetailPage";
import { SettingsPage } from "./popup/Settings";
@@ -64,11 +62,11 @@ if (document.readyState === "loading") {
}
function Application() {
- const [talerActionUrl, setDismissed] = useTalerActionURL()
+ const [talerActionUrl, setDismissed] = useTalerActionURL();
useEffect(() => {
- if (talerActionUrl) route(Pages.cta)
- },[talerActionUrl])
+ if (talerActionUrl) route(Pages.cta);
+ }, [talerActionUrl]);
return (
<div>
@@ -78,33 +76,54 @@ function Application() {
<Router history={createHashHistory()}>
<Route path={Pages.dev} component={DeveloperPage} />
- <Route path={Pages.balance} component={BalancePage}
- goToWalletManualWithdraw={() => goToWalletPage(Pages.manual_withdraw)}
+ <Route
+ path={Pages.balance}
+ component={BalancePage}
+ goToWalletManualWithdraw={() =>
+ goToWalletPage(Pages.manual_withdraw)
+ }
/>
<Route path={Pages.settings} component={SettingsPage} />
- <Route path={Pages.cta} component={() => <TalerActionFound url={talerActionUrl!} onDismiss={() => {
- setDismissed(true)
- route(Pages.balance)
- }} />} />
+ <Route
+ path={Pages.cta}
+ component={() => (
+ <TalerActionFound
+ url={talerActionUrl!}
+ onDismiss={() => {
+ setDismissed(true);
+ route(Pages.balance);
+ }}
+ />
+ )}
+ />
- <Route path={Pages.transaction}
- component={({ tid }: { tid: string }) => goToWalletPage(Pages.transaction.replace(':tid', tid))}
+ <Route
+ path={Pages.transaction}
+ component={({ tid }: { tid: string }) =>
+ goToWalletPage(Pages.transaction.replace(":tid", tid))
+ }
/>
<Route path={Pages.history} component={HistoryPage} />
- <Route path={Pages.backup} component={BackupPage}
+ <Route
+ path={Pages.backup}
+ component={BackupPage}
onAddProvider={() => {
- route(Pages.provider_add)
+ route(Pages.provider_add);
}}
/>
- <Route path={Pages.provider_detail} component={ProviderDetailPage}
+ <Route
+ path={Pages.provider_detail}
+ component={ProviderDetailPage}
onBack={() => {
- route(Pages.backup)
+ route(Pages.backup);
}}
/>
- <Route path={Pages.provider_add} component={ProviderAddPage}
+ <Route
+ path={Pages.provider_add}
+ component={ProviderAddPage}
onBack={() => {
- route(Pages.backup)
+ route(Pages.backup);
}}
/>
<Route default component={Redirect} to={Pages.balance} />
@@ -119,13 +138,13 @@ function goToWalletPage(page: Pages | string): null {
chrome.tabs.create({
active: true,
url: chrome.extension.getURL(`/static/wallet.html#${page}`),
- })
- return null
+ });
+ return null;
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
- route(to, true)
- })
- return null
+ route(to, true);
+ });
+ return null;
}
diff --git a/packages/taler-wallet-webextension/src/renderHtml.tsx b/packages/taler-wallet-webextension/src/renderHtml.tsx
index bbe8e465c..9c2a794dd 100644
--- a/packages/taler-wallet-webextension/src/renderHtml.tsx
+++ b/packages/taler-wallet-webextension/src/renderHtml.tsx
@@ -87,10 +87,7 @@ interface CollapsibleProps {
* Component that shows/hides its children when clicking
* a heading.
*/
-export class Collapsible extends Component<
- CollapsibleProps,
- CollapsibleState
-> {
+export class Collapsible extends Component<CollapsibleProps, CollapsibleState> {
constructor(props: CollapsibleProps) {
super(props);
this.state = { collapsed: props.initiallyCollapsed };
@@ -139,23 +136,20 @@ export function ExpanderText({ text }: ExpanderTextProps): JSX.Element {
return <span>{text}</span>;
}
-export interface LoadingButtonProps extends JSX.HTMLAttributes<HTMLButtonElement> {
+export interface LoadingButtonProps
+ extends JSX.HTMLAttributes<HTMLButtonElement> {
isLoading: boolean;
}
-export function ProgressButton({isLoading, ...rest}: LoadingButtonProps): JSX.Element {
+export function ProgressButton({
+ isLoading,
+ ...rest
+}: LoadingButtonProps): JSX.Element {
return (
- <button
- class="pure-button pure-button-primary"
- type="button"
- {...rest}
- >
+ <button class="pure-button pure-button-primary" type="button" {...rest}>
{isLoading ? (
<span>
- <object
- class="svg-icon svg-baseline"
- data="/img/spinner-bars.svg"
- />
+ <object class="svg-icon svg-baseline" data="/img/spinner-bars.svg" />
</span>
) : null}{" "}
{rest.children}
@@ -163,17 +157,13 @@ export function ProgressButton({isLoading, ...rest}: LoadingButtonProps): JSX.El
);
}
-export function PageLink(
- props: { pageName: string, children?: ComponentChildren },
-): JSX.Element {
+export function PageLink(props: {
+ pageName: string;
+ children?: ComponentChildren;
+}): JSX.Element {
const url = chrome.extension.getURL(`/static/wallet.html#/${props.pageName}`);
return (
- <a
- class="actionLink"
- href={url}
- target="_blank"
- rel="noopener noreferrer"
- >
+ <a class="actionLink" href={url} target="_blank" rel="noopener noreferrer">
{props.children}
</a>
);
diff --git a/packages/taler-wallet-webextension/src/test-utils.ts b/packages/taler-wallet-webextension/src/test-utils.ts
index 6bf1be3ff..28622bb85 100644
--- a/packages/taler-wallet-webextension/src/test-utils.ts
+++ b/packages/taler-wallet-webextension/src/test-utils.ts
@@ -14,15 +14,17 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { ComponentChildren, FunctionalComponent, h as render } from 'preact';
+import { ComponentChildren, FunctionalComponent, h as render } from "preact";
-export function createExample<Props>(Component: FunctionalComponent<Props>, props: Partial<Props>) {
- const r = (args: any) => render(Component, args)
- r.args = props
- return r
+export function createExample<Props>(
+ Component: FunctionalComponent<Props>,
+ props: Partial<Props>,
+) {
+ const r = (args: any) => render(Component, args);
+ r.args = props;
+ return r;
}
-
export function NullLink({ children }: { children?: ComponentChildren }) {
- return render('a', { children, href: 'javascript:void(0);' })
+ return render("a", { children, href: "javascript:void(0);" });
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
index 9a53fefe2..b2771bc2a 100644
--- a/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Backup.stories.tsx
@@ -15,179 +15,184 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { addDays } from 'date-fns';
-import { BackupView as TestedComponent } from './BackupPage';
-import { createExample } from '../test-utils';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { addDays } from "date-fns";
+import { BackupView as TestedComponent } from "./BackupPage";
+import { createExample } from "../test-utils";
export default {
- title: 'wallet/backup/list',
+ title: "wallet/backup/list",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const LotOfProviders = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": addDays(new Date(), 13).getTime()
- }
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: addDays(new Date(), 13).getTime(),
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
- newTerms: {
- annualFee: 'USD:2',
- storageLimitInMegabytes: 8,
- supportedProtocolVersion: '2',
- },
- oldTerms: {
- annualFee: 'USD:1',
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
+ newTerms: {
+ annualFee: "USD:2",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "2",
+ },
+ oldTerms: {
+ annualFee: "USD:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "1",
+ },
+ paidUntil: {
+ t_ms: "never",
+ },
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
storageLimitInMegabytes: 16,
- supportedProtocolVersion: '1',
-
+ supportedProtocolVersion: "0.0",
},
- paidUntil: {
- t_ms: 'never'
- }
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }, {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
+ {
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "KUDOS:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "KUDOS:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const OneProvider = createExample(TestedComponent, {
- providers: [{
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
- ],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ providers: [
+ {
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
+ ],
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "ARS:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
},
- "terms": {
- "annualFee": "ARS:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }]
+ ],
});
-
export const Empty = createExample(TestedComponent, {
- providers: []
+ providers: [],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
index 712329bf8..c3be0203e 100644
--- a/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BackupPage.tsx
@@ -14,15 +14,29 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus } from "@gnu-taler/taler-wallet-core";
-import { differenceInMonths, formatDuration, intervalToDuration } from "date-fns";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+} from "@gnu-taler/taler-wallet-core";
+import {
+ differenceInMonths,
+ formatDuration,
+ intervalToDuration,
+} from "date-fns";
import { Fragment, JSX, VNode, h } from "preact";
import {
- BoldLight, ButtonPrimary, ButtonSuccess, Centered,
- CenteredText, CenteredBoldText, PopupBox, RowBorderGray,
- SmallText, SmallLightText, WalletBox
+ BoldLight,
+ ButtonPrimary,
+ ButtonSuccess,
+ Centered,
+ CenteredText,
+ CenteredBoldText,
+ PopupBox,
+ RowBorderGray,
+ SmallText,
+ SmallLightText,
+ WalletBox,
} from "../components/styled";
import { useBackupStatus } from "../hooks/useBackupStatus";
import { Pages } from "../NavigationBar";
@@ -32,49 +46,68 @@ interface Props {
}
export function BackupPage({ onAddProvider }: Props): VNode {
- const status = useBackupStatus()
+ const status = useBackupStatus();
if (!status) {
- return <div>Loading...</div>
+ return <div>Loading...</div>;
}
- return <BackupView providers={status.providers} onAddProvider={onAddProvider} onSyncAll={status.sync} />;
+ return (
+ <BackupView
+ providers={status.providers}
+ onAddProvider={onAddProvider}
+ onSyncAll={status.sync}
+ />
+ );
}
export interface ViewProps {
- providers: ProviderInfo[],
+ providers: ProviderInfo[];
onAddProvider: () => void;
onSyncAll: () => Promise<void>;
}
-export function BackupView({ providers, onAddProvider, onSyncAll }: ViewProps): VNode {
+export function BackupView({
+ providers,
+ onAddProvider,
+ onSyncAll,
+}: ViewProps): VNode {
return (
<WalletBox>
<section>
- {providers.map((provider) => <BackupLayout
- status={provider.paymentStatus}
- timestamp={provider.lastSuccessfulBackupTimestamp}
- id={provider.syncProviderBaseUrl}
- active={provider.active}
- title={provider.name}
- />
+ {providers.map((provider) => (
+ <BackupLayout
+ status={provider.paymentStatus}
+ timestamp={provider.lastSuccessfulBackupTimestamp}
+ id={provider.syncProviderBaseUrl}
+ active={provider.active}
+ title={provider.name}
+ />
+ ))}
+ {!providers.length && (
+ <Centered style={{ marginTop: 100 }}>
+ <BoldLight>No backup providers configured</BoldLight>
+ <ButtonSuccess onClick={onAddProvider}>
+ <i18n.Translate>Add provider</i18n.Translate>
+ </ButtonSuccess>
+ </Centered>
)}
- {!providers.length && <Centered style={{ marginTop: 100 }}>
- <BoldLight>No backup providers configured</BoldLight>
- <ButtonSuccess onClick={onAddProvider}><i18n.Translate>Add provider</i18n.Translate></ButtonSuccess>
- </Centered>}
</section>
- {!!providers.length && <footer>
- <div />
- <div>
- <ButtonPrimary onClick={onSyncAll}>{
- providers.length > 1 ?
- <i18n.Translate>Sync all backups</i18n.Translate> :
- <i18n.Translate>Sync now</i18n.Translate>
- }</ButtonPrimary>
- <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
- </div>
- </footer>}
+ {!!providers.length && (
+ <footer>
+ <div />
+ <div>
+ <ButtonPrimary onClick={onSyncAll}>
+ {providers.length > 1 ? (
+ <i18n.Translate>Sync all backups</i18n.Translate>
+ ) : (
+ <i18n.Translate>Sync now</i18n.Translate>
+ )}
+ </ButtonPrimary>
+ <ButtonSuccess onClick={onAddProvider}>Add provider</ButtonSuccess>
+ </div>
+ </footer>
+ )}
</WalletBox>
- )
+ );
}
interface TransactionLayoutProps {
@@ -92,55 +125,73 @@ function BackupLayout(props: TransactionLayoutProps): JSX.Element {
timeStyle: "short",
} as any);
-
return (
<RowBorderGray>
<div style={{ color: !props.active ? "grey" : undefined }}>
- <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 && <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>}
+ <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 && (
+ <SmallLightText style={{ marginTop: 5 }}>Not synced</SmallLightText>
+ )}
</div>
<div>
- {props.status?.type === 'paid' ?
- <ExpirationText until={props.status.paidUntil} /> :
+ {props.status?.type === "paid" ? (
+ <ExpirationText until={props.status.paidUntil} />
+ ) : (
<div>{props.status.type}</div>
- }
+ )}
</div>
</RowBorderGray>
);
}
function ExpirationText({ until }: { until: Timestamp }) {
- return <Fragment>
- <CenteredText> Expires in </CenteredText>
- <CenteredBoldText {...({ color: colorByTimeToExpire(until) })}> {daysUntil(until)} </CenteredBoldText>
- </Fragment>
+ return (
+ <Fragment>
+ <CenteredText> Expires in </CenteredText>
+ <CenteredBoldText {...{ color: colorByTimeToExpire(until) }}>
+ {" "}
+ {daysUntil(until)}{" "}
+ </CenteredBoldText>
+ </Fragment>
+ );
}
function colorByTimeToExpire(d: Timestamp) {
- if (d.t_ms === 'never') return 'rgb(28, 184, 65)'
- const months = differenceInMonths(d.t_ms, new Date())
- return months > 1 ? 'rgb(28, 184, 65)' : 'rgb(223, 117, 20)';
+ if (d.t_ms === "never") return "rgb(28, 184, 65)";
+ const months = differenceInMonths(d.t_ms, new Date());
+ return months > 1 ? "rgb(28, 184, 65)" : "rgb(223, 117, 20)";
}
function daysUntil(d: Timestamp) {
- if (d.t_ms === 'never') return undefined
+ if (d.t_ms === "never") return undefined;
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? 'years' : (
- duration?.months ? 'months' : (
- duration?.days ? 'days' : (
- duration.hours ? 'hours' : 'minutes'
- )
- )
- )
- ]
- })
- return `${str}`
-} \ No newline at end of file
+ duration?.years
+ ? "years"
+ : duration?.months
+ ? "months"
+ : duration?.days
+ ? "days"
+ : duration.hours
+ ? "hours"
+ : "minutes",
+ ],
+ });
+ return `${str}`;
+}
diff --git a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
index cccda203e..2432c31eb 100644
--- a/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Balance.stories.tsx
@@ -15,28 +15,25 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample, NullLink } from '../test-utils';
-import { BalanceView as TestedComponent } from './BalancePage';
+import { createExample, NullLink } from "../test-utils";
+import { BalanceView as TestedComponent } from "./BalancePage";
export default {
- title: 'wallet/balance',
+ title: "wallet/balance",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
-export const NotYetLoaded = createExample(TestedComponent, {
-});
+export const NotYetLoaded = createExample(TestedComponent, {});
export const GotError = createExample(TestedComponent, {
balance: {
hasError: true,
- message: 'Network error'
+ message: "Network error",
},
Linker: NullLink,
});
@@ -45,7 +42,7 @@ export const EmptyBalance = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: []
+ balances: [],
},
},
Linker: NullLink,
@@ -55,13 +52,15 @@ export const SomeCoins = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:10.5',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:10.5",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -71,13 +70,15 @@ export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2.23',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5.11',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2.23",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5.11",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
@@ -87,19 +88,22 @@ export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, {
balance: {
hasError: false,
response: {
- balances: [{
- available: 'USD:2',
- hasPendingTransactions: false,
- pendingIncoming: 'USD:5',
- pendingOutgoing: 'USD:0',
- requiresUserInput: false
- },{
- available: 'EUR:4',
- hasPendingTransactions: false,
- pendingIncoming: 'EUR:5',
- pendingOutgoing: 'EUR:0',
- requiresUserInput: false
- }]
+ balances: [
+ {
+ available: "USD:2",
+ hasPendingTransactions: false,
+ pendingIncoming: "USD:5",
+ pendingOutgoing: "USD:0",
+ requiresUserInput: false,
+ },
+ {
+ available: "EUR:4",
+ hasPendingTransactions: false,
+ pendingIncoming: "EUR:5",
+ pendingOutgoing: "EUR:0",
+ requiresUserInput: false,
+ },
+ ],
},
},
Linker: NullLink,
diff --git a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
index eb5a0447c..f3c08a3e8 100644
--- a/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/BalancePage.tsx
@@ -15,19 +15,30 @@
*/
import {
- amountFractionalBase, Amounts,
- Balance, BalancesResponse,
- i18n
+ amountFractionalBase,
+ Amounts,
+ Balance,
+ BalancesResponse,
+ i18n,
} from "@gnu-taler/taler-util";
-import { JSX } from "preact";
+import { JSX, h } from "preact";
import { ButtonPrimary, Centered, WalletBox } from "../components/styled/index";
import { BalancesHook, useBalances } from "../hooks/useBalances";
import { PageLink, renderAmount } from "../renderHtml";
-
-export function BalancePage({ goToWalletManualWithdraw }: { goToWalletManualWithdraw: () => void }) {
- const balance = useBalances()
- return <BalanceView balance={balance} Linker={PageLink} goToWalletManualWithdraw={goToWalletManualWithdraw} />
+export function BalancePage({
+ goToWalletManualWithdraw,
+}: {
+ goToWalletManualWithdraw: () => void;
+}) {
+ const balance = useBalances();
+ return (
+ <BalanceView
+ balance={balance}
+ Linker={PageLink}
+ goToWalletManualWithdraw={goToWalletManualWithdraw}
+ />
+ );
}
export interface BalanceViewProps {
@@ -36,9 +47,13 @@ export interface BalanceViewProps {
goToWalletManualWithdraw: () => void;
}
-export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) {
+export function BalanceView({
+ balance,
+ Linker,
+ goToWalletManualWithdraw,
+}: BalanceViewProps) {
if (!balance) {
- return <span />
+ return <span />;
}
if (balance.hasError) {
@@ -50,19 +65,24 @@ export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: Balan
diagnostics.
</p>
</div>
- )
+ );
}
if (balance.response.balances.length === 0) {
return (
- <p><i18n.Translate>
- You have no balance to show. Need some{" "}
- <Linker pageName="/welcome">help</Linker> getting started?
- </i18n.Translate></p>
- )
+ <p>
+ <i18n.Translate>
+ You have no balance to show. Need some{" "}
+ <Linker pageName="/welcome">help</Linker> getting started?
+ </i18n.Translate>
+ </p>
+ );
}
- return <ShowBalances wallet={balance.response}
- onWithdraw={goToWalletManualWithdraw}
- />
+ return (
+ <ShowBalances
+ wallet={balance.response}
+ onWithdraw={goToWalletManualWithdraw}
+ />
+ );
}
function formatPending(entry: Balance): JSX.Element {
@@ -75,13 +95,15 @@ function formatPending(entry: Balance): JSX.Element {
if (!Amounts.isZero(pendingIncoming)) {
incoming = (
- <span><i18n.Translate>
- <span style={{ color: "darkgreen" }}>
- {"+"}
- {renderAmount(entry.pendingIncoming)}
- </span>{" "}
- incoming
- </i18n.Translate></span>
+ <span>
+ <i18n.Translate>
+ <span style={{ color: "darkgreen" }}>
+ {"+"}
+ {renderAmount(entry.pendingIncoming)}
+ </span>{" "}
+ incoming
+ </i18n.Translate>
+ </span>
);
}
@@ -100,27 +122,36 @@ function formatPending(entry: Balance): JSX.Element {
);
}
-
-function ShowBalances({ wallet, onWithdraw }: { wallet: BalancesResponse, onWithdraw: () => void }) {
- return <WalletBox>
- <section>
- <Centered>{wallet.balances.map((entry) => {
- const av = Amounts.parseOrThrow(entry.available);
- const v = av.value + av.fraction / amountFractionalBase;
- return (
- <p key={av.currency}>
- <span>
- <span style={{ fontSize: "5em", display: "block" }}>{v}</span>{" "}
- <span>{av.currency}</span>
- </span>
- {formatPending(entry)}
- </p>
- );
- })}</Centered>
- </section>
- <footer>
- <div />
- <ButtonPrimary onClick={onWithdraw} >Withdraw</ButtonPrimary>
- </footer>
- </WalletBox>
+function ShowBalances({
+ wallet,
+ onWithdraw,
+}: {
+ wallet: BalancesResponse;
+ onWithdraw: () => void;
+}) {
+ return (
+ <WalletBox>
+ <section>
+ <Centered>
+ {wallet.balances.map((entry) => {
+ const av = Amounts.parseOrThrow(entry.available);
+ const v = av.value + av.fraction / amountFractionalBase;
+ return (
+ <p key={av.currency}>
+ <span>
+ <span style={{ fontSize: "5em", display: "block" }}>{v}</span>{" "}
+ <span>{av.currency}</span>
+ </span>
+ {formatPending(entry)}
+ </p>
+ );
+ })}
+ </Centered>
+ </section>
+ <footer>
+ <div />
+ <ButtonPrimary onClick={onWithdraw}>Withdraw</ButtonPrimary>
+ </footer>
+ </WalletBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
index 35da52392..6eab8dc3a 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.stories.tsx
@@ -15,42 +15,39 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { CreateManualWithdraw as TestedComponent } from './CreateManualWithdraw';
+import { createExample } from "../test-utils";
+import { CreateManualWithdraw as TestedComponent } from "./CreateManualWithdraw";
export default {
- title: 'wallet/manual withdraw/creation',
+ title: "wallet/manual withdraw/creation",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
-export const InitialState = createExample(TestedComponent, {
-});
+export const InitialState = createExample(TestedComponent, {});
export const WithExchangeFilled = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
});
export const WithExchangeAndAmountFilled = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
- initialAmount: '10'
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
+ initialAmount: "10",
});
export const WithExchangeError = createExample(TestedComponent, {
- initialExchange: 'http://exchange.tal',
- error: 'The exchange url seems invalid'
+ initialExchange: "http://exchange.tal",
+ error: "The exchange url seems invalid",
});
export const WithAmountError = createExample(TestedComponent, {
- currency: 'COL',
- initialExchange: 'http://exchange.taler:8081',
- initialAmount: 'e'
+ currency: "COL",
+ initialExchange: "http://exchange.taler:8081",
+ initialAmount: "e",
});
diff --git a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
index be2cbe41d..b48dcbaf2 100644
--- a/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/CreateManualWithdraw.tsx
@@ -1,8 +1,35 @@
+/*
+ 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 { AmountJson, Amounts } from "@gnu-taler/taler-util";
-import { VNode } from "preact";
+import { VNode, h } from "preact";
import { useEffect, useRef, useState } from "preact/hooks";
import { ErrorMessage } from "../components/ErrorMessage";
-import { ButtonPrimary, Input, InputWithLabel, LightText, WalletBox } from "../components/styled";
+import {
+ ButtonPrimary,
+ Input,
+ InputWithLabel,
+ LightText,
+ WalletBox,
+} from "../components/styled";
export interface Props {
error: string | undefined;
@@ -13,44 +40,73 @@ export interface Props {
onCreate: (exchangeBaseUrl: string, amount: AmountJson) => Promise<void>;
}
-export function CreateManualWithdraw({ onExchangeChange, initialExchange, initialAmount, error, currency, onCreate }: Props): VNode {
+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}`)
+ const parsedAmount = Amounts.parse(`${currency}:${amount}`);
let timeout = useRef<number | undefined>(undefined);
useEffect(() => {
- if (timeout) window.clearTimeout(timeout.current)
+ if (timeout) window.clearTimeout(timeout.current);
timeout.current = window.setTimeout(async () => {
- onExchangeChange(exchange)
+ onExchangeChange(exchange);
}, 1000);
- }, [exchange])
-
+ }, [exchange]);
return (
<WalletBox>
<section>
- <ErrorMessage title={error && "Can't create the reserve"} description={error} />
+ <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>
+ <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)} />
+ <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>}
+ {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>
+ <ButtonPrimary
+ disabled={!parsedAmount || !exchange}
+ onClick={() => onCreate(exchange, parsedAmount!)}
+ >
+ Create
+ </ButtonPrimary>
</footer>
</WalletBox>
);
diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
index 0ac4be9a6..9ae3ac3bd 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx
@@ -15,133 +15,146 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import {
PaymentStatus,
- TransactionCommon, TransactionDeposit, TransactionPayment,
- TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+ TransactionCommon,
+ TransactionDeposit,
+ TransactionPayment,
+ TransactionRefresh,
+ TransactionRefund,
+ TransactionTip,
+ TransactionType,
TransactionWithdrawal,
- WithdrawalType
-} from '@gnu-taler/taler-util';
-import { HistoryView as TestedComponent } from './History';
-import { createExample } from '../test-utils';
-
+ WithdrawalType,
+} from "@gnu-taler/taler-util";
+import { HistoryView as TestedComponent } from "./History";
+import { createExample } from "../test-utils";
export default {
- title: 'wallet/history/list',
+ title: "wallet/history/list",
component: TestedComponent,
};
-let count = 0
-const commonTransaction = () => ({
- amountRaw: 'USD:10',
- amountEffective: 'USD:9',
- pending: false,
- timestamp: {
- t_ms: new Date().getTime() - (count++ * 1000 * 60 * 60 * 7)
- },
- transactionId: '12',
-} as TransactionCommon)
+let count = 0;
+const commonTransaction = () =>
+ ({
+ amountRaw: "USD:10",
+ amountEffective: "USD:9",
+ pending: false,
+ timestamp: {
+ t_ms: new Date().getTime() - count++ * 1000 * 60 * 60 * 7,
+ },
+ transactionId: "12",
+ } as TransactionCommon);
const exampleData = {
withdraw: {
...commonTransaction(),
type: TransactionType.Withdrawal,
- exchangeBaseUrl: 'http://exchange.demo.taler.net',
+ exchangeBaseUrl: "http://exchange.demo.taler.net",
withdrawalDetails: {
confirmed: false,
- exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+ exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
- }
+ },
} as TransactionWithdrawal,
payment: {
...commonTransaction(),
- amountEffective: 'USD:11',
+ amountEffective: "USD:11",
type: TransactionType.Payment,
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'Blog',
+ name: "Blog",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
- proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
deposit: {
...commonTransaction(),
type: TransactionType.Deposit,
- depositGroupId: '#groupId',
- targetPaytoUri: 'payto://x-taler-bank/bank/account',
+ depositGroupId: "#groupId",
+ targetPaytoUri: "payto://x-taler-bank/bank/account",
} as TransactionDeposit,
refresh: {
...commonTransaction(),
type: TransactionType.Refresh,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
} as TransactionRefresh,
tip: {
...commonTransaction(),
type: TransactionType.Tip,
- merchantBaseUrl: 'http://ads.merchant.taler.net/',
+ merchantBaseUrl: "http://ads.merchant.taler.net/",
} as TransactionTip,
refund: {
...commonTransaction(),
type: TransactionType.Refund,
- refundedTransactionId: 'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ refundedTransactionId:
+ "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
} as TransactionRefund,
-}
+};
export const Empty = createExample(TestedComponent, {
list: [],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
-
export const One = createExample(TestedComponent, {
list: [exampleData.withdraw],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const OnePending = createExample(TestedComponent, {
- list: [{
- ...exampleData.withdraw,
- pending: true
- }],
- balances: [{
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ list: [
+ {
+ ...exampleData.withdraw,
+ pending: true,
+ },
+ ],
+ balances: [
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const Several = createExample(TestedComponent, {
@@ -154,20 +167,23 @@ export const Several = createExample(TestedComponent, {
...exampleData.payment,
info: {
...exampleData.payment.info,
- summary: 'this is a long summary that may be cropped because its too long',
+ summary:
+ "this is a long summary that may be cropped because its too long",
},
},
exampleData.refund,
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
@@ -181,18 +197,20 @@ export const SeveralWithTwoCurrencies = createExample(TestedComponent, {
exampleData.tip,
exampleData.deposit,
],
- balances: [{
- available: 'TESTKUDOS:10',
- pendingIncoming: 'TESTKUDOS:0',
- pendingOutgoing: 'TESTKUDOS:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }, {
- available: 'USD:10',
- pendingIncoming: 'USD:0',
- pendingOutgoing: 'USD:0',
- hasPendingTransactions: false,
- requiresUserInput: false,
- }]
+ balances: [
+ {
+ available: "TESTKUDOS:10",
+ pendingIncoming: "TESTKUDOS:0",
+ pendingOutgoing: "TESTKUDOS:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ {
+ available: "USD:10",
+ pendingIncoming: "USD:0",
+ pendingOutgoing: "USD:0",
+ hasPendingTransactions: false,
+ requiresUserInput: false,
+ },
+ ],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx
index 8160f8574..aabe50a29 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -14,7 +14,12 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountString, Balance, Transaction, TransactionsResponse } from "@gnu-taler/taler-util";
+import {
+ AmountString,
+ Balance,
+ Transaction,
+ TransactionsResponse,
+} from "@gnu-taler/taler-util";
import { format } from "date-fns";
import { Fragment, h, JSX } from "preact";
import { useEffect, useState } from "preact/hooks";
@@ -23,13 +28,14 @@ import { TransactionItem } from "../components/TransactionItem";
import { useBalances } from "../hooks/useBalances";
import * as wxApi from "../wxApi";
-
export function HistoryPage(props: any): JSX.Element {
const [transactions, setTransactions] = useState<
TransactionsResponse | undefined
>(undefined);
- const balance = useBalances()
- const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || [])
+ const balance = useBalances();
+ const balanceWithoutError = balance?.hasError
+ ? []
+ : balance?.response.balances || [];
useEffect(() => {
const fetchData = async (): Promise<void> => {
@@ -43,45 +49,74 @@ export function HistoryPage(props: any): JSX.Element {
return <div>Loading ...</div>;
}
- return <HistoryView balances={balanceWithoutError} list={[...transactions.transactions].reverse()} />;
+ return (
+ <HistoryView
+ balances={balanceWithoutError}
+ list={[...transactions.transactions].reverse()}
+ />
+ );
}
function amountToString(c: AmountString) {
- const idx = c.indexOf(':')
- return `${c.substring(idx + 1)} ${c.substring(0, idx)}`
+ const idx = c.indexOf(":");
+ return `${c.substring(idx + 1)} ${c.substring(0, idx)}`;
}
-
-
-export function HistoryView({ list, balances }: { list: Transaction[], balances: Balance[] }) {
+export function HistoryView({
+ list,
+ balances,
+}: {
+ list: Transaction[];
+ balances: Balance[];
+}) {
const byDate = list.reduce(function (rv, x) {
- const theDate = x.timestamp.t_ms === "never" ? "never" : format(x.timestamp.t_ms, 'dd MMMM yyyy');
+ const theDate =
+ x.timestamp.t_ms === "never"
+ ? "never"
+ : format(x.timestamp.t_ms, "dd MMMM yyyy");
(rv[theDate] = rv[theDate] || []).push(x);
return rv;
}, {} as { [x: string]: Transaction[] });
- const multiCurrency = balances.length > 1
+ const multiCurrency = balances.length > 1;
- return <WalletBox noPadding>
- {balances.length > 0 && <header>
- {balances.length === 1 && <div class="title">
- Balance: <span>{amountToString(balances[0].available)}</span>
- </div>}
- {balances.length > 1 && <div class="title">
- Balance: <ul style={{ margin: 0 }}>
- {balances.map(b => <li>{b.available}</li>)}
- </ul>
- </div>}
- </header>}
- <section>
- {Object.keys(byDate).map((d,i) => {
- return <Fragment key={i}>
- <DateSeparator>{d}</DateSeparator>
- {byDate[d].map((tx, i) => (
- <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency}/>
- ))}
- </Fragment>
- })}
- </section>
- </WalletBox>
+ return (
+ <WalletBox noPadding>
+ {balances.length > 0 && (
+ <header>
+ {balances.length === 1 && (
+ <div class="title">
+ Balance: <span>{amountToString(balances[0].available)}</span>
+ </div>
+ )}
+ {balances.length > 1 && (
+ <div class="title">
+ Balance:{" "}
+ <ul style={{ margin: 0 }}>
+ {balances.map((b) => (
+ <li>{b.available}</li>
+ ))}
+ </ul>
+ </div>
+ )}
+ </header>
+ )}
+ <section>
+ {Object.keys(byDate).map((d, i) => {
+ return (
+ <Fragment key={i}>
+ <DateSeparator>{d}</DateSeparator>
+ {byDate[d].map((tx, i) => (
+ <TransactionItem
+ key={i}
+ tx={tx}
+ multiCurrency={multiCurrency}
+ />
+ ))}
+ </Fragment>
+ );
+ })}
+ </section>
+ </WalletBox>
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index dcc0002e6..102978f9e 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -14,68 +14,84 @@
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 { VNode, h } from "preact";
+import { useState } from "preact/hooks";
import { CreateManualWithdraw } from "./CreateManualWithdraw";
-import * as wxApi from '../wxApi'
-import { AcceptManualWithdrawalResult, AmountJson, Amounts } from "@gnu-taler/taler-util";
+import * as wxApi from "../wxApi";
+import {
+ AcceptManualWithdrawalResult,
+ AmountJson,
+ Amounts,
+} from "@gnu-taler/taler-util";
import { ReserveCreated } from "./ReserveCreated.js";
-import { route } from 'preact-router';
+import { route } from "preact-router";
import { Pages } from "../NavigationBar.js";
-interface Props {
-
-}
+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)
+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
+ async function onExchangeChange(exchange: string | undefined): Promise<void> {
+ if (!exchange) return;
try {
- const r = await fetch(`${exchange}/keys`)
- const j = await r.json()
+ const r = await fetch(`${exchange}/keys`);
+ const j = await r.json();
if (j.currency) {
await wxApi.addExchange({
exchangeBaseUrl: `${exchange}/`,
- forceUpdate: true
- })
- setCurrency(j.currency)
+ forceUpdate: true,
+ });
+ setCurrency(j.currency);
}
} catch (e) {
- setError('The exchange url seems invalid')
- setCurrency(undefined)
+ setError("The exchange url seems invalid");
+ setCurrency(undefined);
}
}
- async function doCreate(exchangeBaseUrl: string, amount: AmountJson) {
+ async function doCreate(
+ exchangeBaseUrl: string,
+ amount: AmountJson,
+ ): Promise<void> {
try {
- const resp = await wxApi.acceptManualWithdrawal(exchangeBaseUrl, Amounts.stringify(amount))
- setSuccess(resp)
+ const resp = await wxApi.acceptManualWithdrawal(
+ exchangeBaseUrl,
+ Amounts.stringify(amount),
+ );
+ setSuccess(resp);
} catch (e) {
if (e instanceof Error) {
- setError(e.message)
+ setError(e.message);
} else {
- setError('unexpected error')
+ setError("unexpected error");
}
- setSuccess(undefined)
+ setSuccess(undefined);
}
}
if (success) {
- return <ReserveCreated reservePub={success.reservePub} paytos={success.exchangePaytoUris} onBack={() => {
- route(Pages.balance)
- }}/>
+ return (
+ <ReserveCreated
+ reservePub={success.reservePub}
+ paytos={success.exchangePaytoUris}
+ onBack={() => {
+ route(Pages.balance);
+ }}
+ />
+ );
}
- return <CreateManualWithdraw
- error={error} currency={currency}
- onCreate={doCreate} onExchangeChange={onExchangeChange}
- />;
+ return (
+ <CreateManualWithdraw
+ error={error}
+ currency={currency}
+ onCreate={doCreate}
+ onExchangeChange={onExchangeChange}
+ />
+ );
}
-
-
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
index d1e76c053..5c4e56b15 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddConfirmProvider.stories.tsx
@@ -15,38 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { ConfirmProviderView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { ConfirmProviderView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'wallet/backup/confirm',
+ title: "wallet/backup/confirm",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const DemoService = createExample(TestedComponent, {
- url: 'https://sync.demo.taler.net/',
+ url: "https://sync.demo.taler.net/",
provider: {
- annual_fee: 'KUDOS:0.1',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "KUDOS:0.1",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
export const FreeService = createExample(TestedComponent, {
- url: 'https://sync.taler:9667/',
+ url: "https://sync.taler:9667/",
provider: {
- annual_fee: 'ARS:0',
- storage_limit_in_megabytes: 20,
- supported_protocol_version: '1'
- }
+ annual_fee: "ARS:0",
+ storage_limit_in_megabytes: 20,
+ supported_protocol_version: "1",
+ },
});
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
index 4890e5e9c..75292b7e4 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderAddSetUrl.stories.tsx
@@ -15,39 +15,37 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SetUrlView as TestedComponent } from './ProviderAddPage';
+import { createExample } from "../test-utils";
+import { SetUrlView as TestedComponent } from "./ProviderAddPage";
export default {
- title: 'wallet/backup/add',
+ title: "wallet/backup/add",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
-export const Initial = createExample(TestedComponent, {
-});
+export const Initial = createExample(TestedComponent, {});
export const WithValue = createExample(TestedComponent, {
- initialValue: 'sync.demo.taler.net'
-});
+ initialValue: "sync.demo.taler.net",
+});
export const WithConnectionError = createExample(TestedComponent, {
- withError: 'Network error'
-});
+ withError: "Network error",
+});
export const WithClientError = createExample(TestedComponent, {
- withError: 'URL may not be right: (404) Not Found'
-});
+ withError: "URL may not be right: (404) Not Found",
+});
export const WithServerError = createExample(TestedComponent, {
- withError: 'Try another server: (500) Internal Server Error'
-});
+ withError: "Try another server: (500) Internal Server Error",
+});
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
index 67ff83442..a170620a3 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetail.stories.tsx
@@ -15,224 +15,221 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { ProviderPaymentType } from '@gnu-taler/taler-wallet-core';
-import { createExample } from '../test-utils';
-import { ProviderView as TestedComponent } from './ProviderDetailPage';
+import { ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import { createExample } from "../test-utils";
+import { ProviderView as TestedComponent } from "./ProviderDetailPage";
export default {
- title: 'wallet/backup/details',
+ title: "wallet/backup/details",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
-
export const Active = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveErrorSync = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
},
lastAttemptedBackupTimestamp: {
- "t_ms": 1625063925078
+ t_ms: 1625063925078,
},
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
lastError: {
code: 2002,
- details: 'details',
- hint: 'error hint from the server',
- message: 'message'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ details: "details",
+ hint: "error hint from the server",
+ message: "message",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemUnreadable = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-unreadable'
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ type: "backup-unreadable",
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const ActiveBackupProblemDevice = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.taler:9967/",
- "lastSuccessfulBackupTimestamp": {
- "t_ms": 1625063925078
- },
- "paymentProposalIds": [
- "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG"
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.taler:9967/",
+ lastSuccessfulBackupTimestamp: {
+ t_ms: 1625063925078,
+ },
+ paymentProposalIds: [
+ "43Q5WWRJPNS4SE9YKS54H9THDS94089EDGXW9EHBPN6E7M184XEG",
],
- "paymentStatus": {
- "type": ProviderPaymentType.Paid,
- "paidUntil": {
- "t_ms": 1656599921000
- }
+ paymentStatus: {
+ type: ProviderPaymentType.Paid,
+ paidUntil: {
+ t_ms: 1656599921000,
+ },
},
backupProblem: {
- type: 'backup-conflicting-device',
- myDeviceId: 'my-device-id',
- otherDeviceId: 'other-device-id',
+ type: "backup-conflicting-device",
+ myDeviceId: "my-device-id",
+ otherDeviceId: "other-device-id",
backupTimestamp: {
- "t_ms": 1656599921000
- }
- },
- "terms": {
- "annualFee": "EUR:1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ t_ms: 1656599921000,
+ },
+ },
+ terms: {
+ annualFee: "EUR:1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveUnpaid = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Unpaid,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Unpaid,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactiveInsufficientBalance = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.InsufficientBalance,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.InsufficientBalance,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
export const InactivePending = createExample(TestedComponent, {
info: {
- "active": false,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.Pending,
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ active: false,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.Pending,
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
export const ActiveTermsChanged = createExample(TestedComponent, {
info: {
- "active": true,
- name:'sync.demo',
- "syncProviderBaseUrl": "http://sync.demo.taler.net/",
- "paymentProposalIds": [],
- "paymentStatus": {
- "type": ProviderPaymentType.TermsChanged,
+ active: true,
+ name: "sync.demo",
+ syncProviderBaseUrl: "http://sync.demo.taler.net/",
+ paymentProposalIds: [],
+ paymentStatus: {
+ type: ProviderPaymentType.TermsChanged,
paidUntil: {
- t_ms: 1656599921000
+ t_ms: 1656599921000,
},
newTerms: {
- "annualFee": "EUR:10",
- "storageLimitInMegabytes": 8,
- "supportedProtocolVersion": "0.0"
+ annualFee: "EUR:10",
+ storageLimitInMegabytes: 8,
+ supportedProtocolVersion: "0.0",
},
oldTerms: {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- },
- "terms": {
- "annualFee": "EUR:0.1",
- "storageLimitInMegabytes": 16,
- "supportedProtocolVersion": "0.0"
- }
- }
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
+ terms: {
+ annualFee: "EUR:0.1",
+ storageLimitInMegabytes: 16,
+ supportedProtocolVersion: "0.0",
+ },
+ },
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
index c45458eb7..bd64b0760 100644
--- a/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ProviderDetailPage.tsx
@@ -14,13 +14,23 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { i18n, Timestamp } from "@gnu-taler/taler-util";
-import { ProviderInfo, ProviderPaymentStatus, ProviderPaymentType } from "@gnu-taler/taler-wallet-core";
+import {
+ ProviderInfo,
+ ProviderPaymentStatus,
+ ProviderPaymentType,
+} from "@gnu-taler/taler-wallet-core";
import { format, formatDuration, intervalToDuration } from "date-fns";
import { Fragment, VNode, h } from "preact";
import { ErrorMessage } from "../components/ErrorMessage";
-import { Button, ButtonDestructive, ButtonPrimary, PaymentStatus, WalletBox, SmallLightText } from "../components/styled";
+import {
+ Button,
+ ButtonDestructive,
+ ButtonPrimary,
+ PaymentStatus,
+ WalletBox,
+ SmallLightText,
+} from "../components/styled";
import { useProviderStatus } from "../hooks/useProviderStatus";
interface Props {
@@ -29,20 +39,29 @@ interface Props {
}
export function ProviderDetailPage({ pid, onBack }: Props): VNode {
- const status = useProviderStatus(pid)
+ const status = useProviderStatus(pid);
if (!status) {
- return <div><i18n.Translate>Loading...</i18n.Translate></div>
+ return (
+ <div>
+ <i18n.Translate>Loading...</i18n.Translate>
+ </div>
+ );
}
if (!status.info) {
- onBack()
- return <div />
+ onBack();
+ return <div />;
}
- return <ProviderView info={status.info}
- onSync={status.sync}
- onDelete={() => status.remove().then(onBack)}
- onBack={onBack}
- onExtend={() => { null }}
- />;
+ return (
+ <ProviderView
+ info={status.info}
+ onSync={status.sync}
+ onDelete={() => status.remove().then(onBack)}
+ onBack={onBack}
+ onExtend={() => {
+ null;
+ }}
+ />
+ );
}
export interface ViewProps {
@@ -53,124 +72,185 @@ export interface ViewProps {
onExtend: () => void;
}
-export function ProviderView({ info, onDelete, onSync, onBack, onExtend }: ViewProps): VNode {
- const lb = info?.lastSuccessfulBackupTimestamp
- const isPaid = info.paymentStatus.type === ProviderPaymentType.Paid || info.paymentStatus.type === ProviderPaymentType.TermsChanged
+export function ProviderView({
+ info,
+ onDelete,
+ onSync,
+ onBack,
+ onExtend,
+}: ViewProps): VNode {
+ const lb = info?.lastSuccessfulBackupTimestamp;
+ const isPaid =
+ info.paymentStatus.type === ProviderPaymentType.Paid ||
+ info.paymentStatus.type === ProviderPaymentType.TermsChanged;
return (
<WalletBox>
<Error info={info} />
<header>
- <h3>{info.name} <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText></h3>
- <PaymentStatus color={isPaid ? 'rgb(28, 184, 65)' : 'rgb(202, 60, 60)'}>{isPaid ? 'Paid' : 'Unpaid'}</PaymentStatus>
+ <h3>
+ {info.name}{" "}
+ <SmallLightText>{info.syncProviderBaseUrl}</SmallLightText>
+ </h3>
+ <PaymentStatus color={isPaid ? "rgb(28, 184, 65)" : "rgb(202, 60, 60)"}>
+ {isPaid ? "Paid" : "Unpaid"}
+ </PaymentStatus>
</header>
<section>
- <p><b>Last backup:</b> {lb == null || lb.t_ms == "never" ? "never" : format(lb.t_ms, 'dd MMM yyyy')} </p>
- <ButtonPrimary onClick={onSync}><i18n.Translate>Back up</i18n.Translate></ButtonPrimary>
- {info.terms && <Fragment>
- <p><b>Provider fee:</b> {info.terms && info.terms.annualFee} per year</p>
- </Fragment>
- }
+ <p>
+ <b>Last backup:</b>{" "}
+ {lb == null || lb.t_ms == "never"
+ ? "never"
+ : format(lb.t_ms, "dd MMM yyyy")}{" "}
+ </p>
+ <ButtonPrimary onClick={onSync}>
+ <i18n.Translate>Back up</i18n.Translate>
+ </ButtonPrimary>
+ {info.terms && (
+ <Fragment>
+ <p>
+ <b>Provider fee:</b> {info.terms && info.terms.annualFee} per year
+ </p>
+ </Fragment>
+ )}
<p>{descriptionByStatus(info.paymentStatus)}</p>
- <ButtonPrimary disabled onClick={onExtend}><i18n.Translate>Extend</i18n.Translate></ButtonPrimary>
-
- {info.paymentStatus.type === ProviderPaymentType.TermsChanged && <div>
- <p><i18n.Translate>terms has changed, extending the service will imply accepting the new terms of service</i18n.Translate></p>
- <table>
- <thead>
- <tr>
- <td></td>
- <td><i18n.Translate>old</i18n.Translate></td>
- <td> -&gt;</td>
- <td><i18n.Translate>new</i18n.Translate></td>
- </tr>
- </thead>
- <tbody>
-
- <tr>
- <td><i18n.Translate>fee</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.annualFee}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.annualFee}</td>
- </tr>
- <tr>
- <td><i18n.Translate>storage</i18n.Translate></td>
- <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
- <td>-&gt;</td>
- <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
- </tr>
- </tbody>
- </table>
- </div>}
+ <ButtonPrimary disabled onClick={onExtend}>
+ <i18n.Translate>Extend</i18n.Translate>
+ </ButtonPrimary>
+ {info.paymentStatus.type === ProviderPaymentType.TermsChanged && (
+ <div>
+ <p>
+ <i18n.Translate>
+ terms has changed, extending the service will imply accepting
+ the new terms of service
+ </i18n.Translate>
+ </p>
+ <table>
+ <thead>
+ <tr>
+ <td></td>
+ <td>
+ <i18n.Translate>old</i18n.Translate>
+ </td>
+ <td> -&gt;</td>
+ <td>
+ <i18n.Translate>new</i18n.Translate>
+ </td>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>
+ <i18n.Translate>fee</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.annualFee}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.annualFee}</td>
+ </tr>
+ <tr>
+ <td>
+ <i18n.Translate>storage</i18n.Translate>
+ </td>
+ <td>{info.paymentStatus.oldTerms.storageLimitInMegabytes}</td>
+ <td>-&gt;</td>
+ <td>{info.paymentStatus.newTerms.storageLimitInMegabytes}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ )}
</section>
<footer>
- <Button onClick={onBack}><i18n.Translate> &lt; back</i18n.Translate></Button>
+ <Button onClick={onBack}>
+ <i18n.Translate> &lt; back</i18n.Translate>
+ </Button>
<div>
- <ButtonDestructive onClick={onDelete}><i18n.Translate>remove provider</i18n.Translate></ButtonDestructive>
+ <ButtonDestructive onClick={onDelete}>
+ <i18n.Translate>remove provider</i18n.Translate>
+ </ButtonDestructive>
</div>
</footer>
</WalletBox>
- )
+ );
}
function daysSince(d?: Timestamp) {
- if (!d || d.t_ms === 'never') return 'never synced'
+ if (!d || d.t_ms === "never") return "never synced";
const duration = intervalToDuration({
start: d.t_ms,
end: new Date(),
- })
+ });
const str = formatDuration(duration, {
- delimiter: ', ',
+ delimiter: ", ",
format: [
- duration?.years ? i18n.str`years` : (
- duration?.months ? i18n.str`months` : (
- duration?.days ? i18n.str`days` : (
- duration?.hours ? i18n.str`hours` : (
- duration?.minutes ? i18n.str`minutes` : i18n.str`seconds`
- )
- )
- )
- )
- ]
- })
- return `synced ${str} ago`
+ duration?.years
+ ? i18n.str`years`
+ : duration?.months
+ ? i18n.str`months`
+ : duration?.days
+ ? i18n.str`days`
+ : duration?.hours
+ ? i18n.str`hours`
+ : duration?.minutes
+ ? i18n.str`minutes`
+ : i18n.str`seconds`,
+ ],
+ });
+ return `synced ${str} ago`;
}
function Error({ info }: { info: ProviderInfo }) {
if (info.lastError) {
- return <ErrorMessage title={info.lastError.hint} />
+ return <ErrorMessage title={info.lastError.hint} />;
}
if (info.backupProblem) {
switch (info.backupProblem.type) {
case "backup-conflicting-device":
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>There is conflict with another backup from <b>{info.backupProblem.otherDeviceId}</b></i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ There is conflict with another backup from{" "}
+ <b>{info.backupProblem.otherDeviceId}</b>
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
case "backup-unreadable":
- return <ErrorMessage title="Backup is not readable" />
+ return <ErrorMessage title="Backup is not readable" />;
default:
- return <ErrorMessage title={<Fragment>
- <i18n.Translate>Unknown backup problem: {JSON.stringify(info.backupProblem)}</i18n.Translate>
- </Fragment>} />
+ return (
+ <ErrorMessage
+ title={
+ <Fragment>
+ <i18n.Translate>
+ Unknown backup problem: {JSON.stringify(info.backupProblem)}
+ </i18n.Translate>
+ </Fragment>
+ }
+ />
+ );
}
}
- return null
+ return null;
}
function colorByStatus(status: ProviderPaymentType) {
switch (status) {
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(223, 117, 20)'
+ return "rgb(223, 117, 20)";
case ProviderPaymentType.Unpaid:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.Paid:
- return 'rgb(28, 184, 65)'
+ return "rgb(28, 184, 65)";
case ProviderPaymentType.Pending:
- return 'gray'
+ return "gray";
case ProviderPaymentType.InsufficientBalance:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
case ProviderPaymentType.TermsChanged:
- return 'rgb(202, 60, 60)'
+ return "rgb(202, 60, 60)";
}
}
@@ -180,16 +260,19 @@ function descriptionByStatus(status: ProviderPaymentStatus) {
// return i18n.str`not paid yet`
case ProviderPaymentType.Paid:
case ProviderPaymentType.TermsChanged:
- if (status.paidUntil.t_ms === 'never') {
- return i18n.str`service paid`
+ if (status.paidUntil.t_ms === "never") {
+ return i18n.str`service paid`;
} else {
- return <Fragment>
- <b>Backup valid until:</b> {format(status.paidUntil.t_ms, 'dd MMM yyyy')}
- </Fragment>
+ return (
+ <Fragment>
+ <b>Backup valid until:</b>{" "}
+ {format(status.paidUntil.t_ms, "dd MMM yyyy")}
+ </Fragment>
+ );
}
case ProviderPaymentType.Unpaid:
case ProviderPaymentType.InsufficientBalance:
case ProviderPaymentType.Pending:
- return ''
+ return "";
}
}
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
index ca524f4e2..c552b19ba 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx
@@ -15,26 +15,23 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { ReserveCreated as TestedComponent } from './ReserveCreated';
+import { createExample } from "../test-utils";
+import { ReserveCreated as TestedComponent } from "./ReserveCreated";
export default {
- title: 'wallet/manual withdraw/reserve created',
+ title: "wallet/manual withdraw/reserve created",
component: TestedComponent,
- argTypes: {
- }
+ argTypes: {},
};
-
export const InitialState = createExample(TestedComponent, {
- reservePub: 'ASLKDJQWLKEJASLKDJSADLKASJDLKSADJ',
+ 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',
- ]
+ "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",
+ ],
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
index e01336e02..9008e9751 100644
--- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.tsx
@@ -1,8 +1,7 @@
-import { Fragment, VNode } from "preact";
+import { h, 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[];
@@ -10,30 +9,57 @@ export interface Props {
}
export function ReserveCreated({ reservePub, paytos, onBack }: Props): VNode {
- const [opened, setOpened] = useState(-1)
+ 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>
+ <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>
+ 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>&#x2190;</FontIcon></ButtonBox>
+ <ButtonBox onClick={onBack}>
+ <FontIcon>&#x2190;</FontIcon>
+ </ButtonBox>
<div />
</footer>
</WalletBox>
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
index a04a0b4fd..6cc1368d5 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.stories.tsx
@@ -15,39 +15,41 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
-import { createExample } from '../test-utils';
-import { SettingsView as TestedComponent } from './Settings';
+import { createExample } from "../test-utils";
+import { SettingsView as TestedComponent } from "./Settings";
export default {
- title: 'wallet/settings',
+ title: "wallet/settings",
component: TestedComponent,
argTypes: {
setDeviceName: () => Promise.resolve(),
- }
+ },
};
export const AllOff = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
setDeviceName: () => Promise.resolve(),
});
export const OneChecked = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
permissionsEnabled: true,
setDeviceName: () => Promise.resolve(),
});
export const WithOneExchange = createExample(TestedComponent, {
- deviceName: 'this-is-the-device-name',
+ deviceName: "this-is-the-device-name",
permissionsEnabled: true,
setDeviceName: () => Promise.resolve(),
- knownExchanges: [{
- currency: 'USD',
- exchangeBaseUrl: 'http://exchange.taler',
- paytoUris: ['payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator']
- }]
+ knownExchanges: [
+ {
+ currency: "USD",
+ exchangeBaseUrl: "http://exchange.taler",
+ paytoUris: ["payto://x-taler-bank/bank.rpi.sebasjm.com/exchangeminator"],
+ },
+ ],
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Settings.tsx b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
index 8d18586b1..8d8f3cdbc 100644
--- a/packages/taler-wallet-webextension/src/wallet/Settings.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Settings.tsx
@@ -14,7 +14,6 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-
import { ExchangeListItem, i18n } from "@gnu-taler/taler-util";
import { VNode, h, Fragment } from "preact";
import { Checkbox } from "../components/Checkbox";
@@ -30,18 +29,28 @@ import * as wxApi from "../wxApi";
export function SettingsPage(): VNode {
const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
- const { devMode, toggleDevMode } = useDevContext()
- const { name, update } = useBackupDeviceName()
- const [lang, changeLang] = useLang()
+ const { devMode, toggleDevMode } = useDevContext();
+ const { name, update } = useBackupDeviceName();
+ const [lang, changeLang] = useLang();
const exchangesHook = useAsyncAsHook(() => wxApi.listExchanges());
- return <SettingsView
- lang={lang} changeLang={changeLang}
- knownExchanges={!exchangesHook || exchangesHook.hasError ? [] : exchangesHook.response.exchanges}
- deviceName={name} setDeviceName={update}
- permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
- developerMode={devMode} toggleDeveloperMode={toggleDevMode}
- />;
+ return (
+ <SettingsView
+ lang={lang}
+ changeLang={changeLang}
+ knownExchanges={
+ !exchangesHook || exchangesHook.hasError
+ ? []
+ : exchangesHook.response.exchanges
+ }
+ deviceName={name}
+ setDeviceName={update}
+ permissionsEnabled={permissionsEnabled}
+ togglePermissions={togglePermissions}
+ developerMode={devMode}
+ toggleDeveloperMode={toggleDevMode}
+ />
+ );
}
export interface ViewProps {
@@ -56,52 +65,72 @@ export interface ViewProps {
knownExchanges: Array<ExchangeListItem>;
}
-import { strings as messages } from '../i18n/strings'
+import { strings as messages } from "../i18n/strings";
type LangsNames = {
- [P in keyof typeof messages]: string
-}
+ [P in keyof typeof messages]: string;
+};
const names: LangsNames = {
- es: 'Español [es]',
- en: 'English [en]',
- fr: 'Français [fr]',
- de: 'Deutsch [de]',
- sv: 'Svenska [sv]',
- it: 'Italiano [it]',
-}
+ es: "Español [es]",
+ en: "English [en]",
+ fr: "Français [fr]",
+ de: "Deutsch [de]",
+ sv: "Svenska [sv]",
+ it: "Italiano [it]",
+};
-
-export function SettingsView({ knownExchanges, lang, changeLang, deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode {
+export function SettingsView({
+ knownExchanges,
+ lang,
+ changeLang,
+ deviceName,
+ setDeviceName,
+ permissionsEnabled,
+ togglePermissions,
+ developerMode,
+ toggleDeveloperMode,
+}: ViewProps): VNode {
return (
<WalletBox>
<section>
-
- <h2><i18n.Translate>Known exchanges</i18n.Translate></h2>
- {!knownExchanges || !knownExchanges.length ? <div>
- No exchange yet!
- </div> :
+ <h2>
+ <i18n.Translate>Known exchanges</i18n.Translate>
+ </h2>
+ {!knownExchanges || !knownExchanges.length ? (
+ <div>No exchange yet!</div>
+ ) : (
<table>
- {knownExchanges.map(e => <tr>
- <td>{e.currency}</td>
- <td><a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a></td>
- </tr>)}
+ {knownExchanges.map((e) => (
+ <tr>
+ <td>{e.currency}</td>
+ <td>
+ <a href={e.exchangeBaseUrl}>{e.exchangeBaseUrl}</a>
+ </td>
+ </tr>
+ ))}
</table>
- }
-
- <h2><i18n.Translate>Permissions</i18n.Translate></h2>
- <Checkbox label="Automatically open wallet based on page content"
+ )}
+
+ <h2>
+ <i18n.Translate>Permissions</i18n.Translate>
+ </h2>
+ <Checkbox
+ label="Automatically open wallet based on page content"
name="perm"
description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
- enabled={permissionsEnabled} onToggle={togglePermissions}
+ enabled={permissionsEnabled}
+ onToggle={togglePermissions}
/>
<h2>Config</h2>
- <Checkbox label="Developer mode"
+ <Checkbox
+ label="Developer mode"
name="devMode"
description="(More options and information useful for debugging)"
- enabled={developerMode} onToggle={toggleDeveloperMode}
+ enabled={developerMode}
+ onToggle={toggleDeveloperMode}
/>
</section>
</WalletBox>
- )
+ );
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
index 535509cef..c9a3f47cb 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.stories.tsx
@@ -15,110 +15,116 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
import {
PaymentStatus,
- TransactionCommon, TransactionDeposit, TransactionPayment,
- TransactionRefresh, TransactionRefund, TransactionTip, TransactionType,
+ TransactionCommon,
+ TransactionDeposit,
+ TransactionPayment,
+ TransactionRefresh,
+ TransactionRefund,
+ TransactionTip,
+ TransactionType,
TransactionWithdrawal,
- WithdrawalType
-} from '@gnu-taler/taler-util';
-import { createExample } from '../test-utils';
-import { TransactionView as TestedComponent } from './Transaction';
+ WithdrawalType,
+} from "@gnu-taler/taler-util";
+import { createExample } from "../test-utils";
+import { TransactionView as TestedComponent } from "./Transaction";
export default {
- title: 'wallet/history/details',
+ title: "wallet/history/details",
component: TestedComponent,
argTypes: {
- onRetry: { action: 'onRetry' },
- onDelete: { action: 'onDelete' },
- onBack: { action: 'onBack' },
- }
+ onRetry: { action: "onRetry" },
+ onDelete: { action: "onDelete" },
+ onBack: { action: "onBack" },
+ },
};
const commonTransaction = {
- amountRaw: 'KUDOS:11',
- amountEffective: 'KUDOS:9.2',
+ amountRaw: "KUDOS:11",
+ amountEffective: "KUDOS:9.2",
pending: false,
timestamp: {
- t_ms: new Date().getTime()
+ t_ms: new Date().getTime(),
},
- transactionId: '12',
-} as TransactionCommon
+ transactionId: "12",
+} as TransactionCommon;
const exampleData = {
withdraw: {
...commonTransaction,
type: TransactionType.Withdrawal,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
withdrawalDetails: {
confirmed: false,
- exchangePaytoUris: ['payto://x-taler-bank/bank/account'],
+ exchangePaytoUris: ["payto://x-taler-bank/bank/account"],
type: WithdrawalType.ManualTransfer,
- }
+ },
} as TransactionWithdrawal,
payment: {
...commonTransaction,
- amountEffective: 'KUDOS:11',
+ amountEffective: "KUDOS:11",
type: TransactionType.Payment,
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
summary: "Essay: Why the Devil's Advocate Doesn't Help Reach the Truth",
- fulfillmentMessage: '',
+ fulfillmentMessage: "",
},
- proposalId: '1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ proposalId: "1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
status: PaymentStatus.Accepted,
} as TransactionPayment,
deposit: {
...commonTransaction,
type: TransactionType.Deposit,
- depositGroupId: '#groupId',
- targetPaytoUri: 'payto://x-taler-bank/bank/account',
+ depositGroupId: "#groupId",
+ targetPaytoUri: "payto://x-taler-bank/bank/account",
} as TransactionDeposit,
refresh: {
...commonTransaction,
type: TransactionType.Refresh,
- exchangeBaseUrl: 'http://exchange.taler',
+ exchangeBaseUrl: "http://exchange.taler",
} as TransactionRefresh,
tip: {
...commonTransaction,
type: TransactionType.Tip,
- merchantBaseUrl: 'http://merchant.taler',
+ merchantBaseUrl: "http://merchant.taler",
} as TransactionTip,
refund: {
...commonTransaction,
type: TransactionType.Refund,
- refundedTransactionId: 'payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0',
+ refundedTransactionId:
+ "payment:1EMJJH8EP1NX3XF7733NCYS2DBEJW4Q2KA5KEB37MCQJQ8Q5HMC0",
info: {
- contractTermsHash: 'ASDZXCASD',
+ contractTermsHash: "ASDZXCASD",
merchant: {
- name: 'the merchant',
+ name: "the merchant",
},
- orderId: '2021.167-03NPY6MCYMVGT',
+ orderId: "2021.167-03NPY6MCYMVGT",
products: [],
- summary: 'the summary',
- fulfillmentMessage: '',
+ summary: "the summary",
+ fulfillmentMessage: "",
},
} as TransactionRefund,
-}
+};
const transactionError = {
code: 2000,
details: "details",
hint: "this is a hint for the error",
- message: 'message'
-}
+ message: "message",
+};
export const Withdraw = createExample(TestedComponent, {
- transaction: exampleData.withdraw
+ transaction: exampleData.withdraw,
});
export const WithdrawError = createExample(TestedComponent, {
@@ -132,24 +138,22 @@ export const WithdrawPending = createExample(TestedComponent, {
transaction: { ...exampleData.withdraw, pending: true },
});
-
export const Payment = createExample(TestedComponent, {
- transaction: exampleData.payment
+ transaction: exampleData.payment,
});
export const PaymentError = createExample(TestedComponent, {
transaction: {
...exampleData.payment,
- error: transactionError
+ error: transactionError,
},
});
export const PaymentWithoutFee = createExample(TestedComponent, {
transaction: {
...exampleData.payment,
- amountRaw: 'KUDOS:11',
-
- }
+ amountRaw: "KUDOS:11",
+ },
});
export const PaymentPending = createExample(TestedComponent, {
@@ -161,27 +165,33 @@ export const PaymentWithProducts = createExample(TestedComponent, {
...exampleData.payment,
info: {
...exampleData.payment.info,
- summary: 'this order has 5 products',
- products: [{
- description: 't-shirt',
- unit: 'shirts',
- quantity: 1,
- }, {
- description: 't-shirt',
- unit: 'shirts',
- quantity: 1,
- }, {
- description: 'e-book',
- }, {
- description: 'beer',
- unit: 'pint',
- quantity: 15,
- }, {
- description: 'beer',
- unit: 'pint',
- quantity: 15,
- }]
- }
+ summary: "this order has 5 products",
+ products: [
+ {
+ description: "t-shirt",
+ unit: "shirts",
+ quantity: 1,
+ },
+ {
+ description: "t-shirt",
+ unit: "shirts",
+ quantity: 1,
+ },
+ {
+ description: "e-book",
+ },
+ {
+ description: "beer",
+ unit: "pint",
+ quantity: 15,
+ },
+ {
+ description: "beer",
+ unit: "pint",
+ quantity: 15,
+ },
+ ],
+ },
} as TransactionPayment,
});
@@ -190,75 +200,79 @@ export const PaymentWithLongSummary = createExample(TestedComponent, {
...exampleData.payment,
info: {
...exampleData.payment.info,
- summary: 'this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, ',
- products: [{
- description: 'an xl sized t-shirt with some drawings on it, color pink',
- unit: 'shirts',
- quantity: 1,
- }, {
- description: 'beer',
- unit: 'pint',
- quantity: 15,
- }]
- }
+ summary:
+ "this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, this is a very long summary that will occupy severals lines, ",
+ products: [
+ {
+ description:
+ "an xl sized t-shirt with some drawings on it, color pink",
+ unit: "shirts",
+ quantity: 1,
+ },
+ {
+ description: "beer",
+ unit: "pint",
+ quantity: 15,
+ },
+ ],
+ },
} as TransactionPayment,
});
-
export const Deposit = createExample(TestedComponent, {
- transaction: exampleData.deposit
+ transaction: exampleData.deposit,
});
export const DepositError = createExample(TestedComponent, {
transaction: {
...exampleData.deposit,
- error: transactionError
+ error: transactionError,
},
});
export const DepositPending = createExample(TestedComponent, {
- transaction: { ...exampleData.deposit, pending: true }
+ transaction: { ...exampleData.deposit, pending: true },
});
export const Refresh = createExample(TestedComponent, {
- transaction: exampleData.refresh
+ transaction: exampleData.refresh,
});
export const RefreshError = createExample(TestedComponent, {
transaction: {
...exampleData.refresh,
- error: transactionError
+ error: transactionError,
},
});
export const Tip = createExample(TestedComponent, {
- transaction: exampleData.tip
+ transaction: exampleData.tip,
});
export const TipError = createExample(TestedComponent, {
transaction: {
...exampleData.tip,
- error: transactionError
+ error: transactionError,
},
});
export const TipPending = createExample(TestedComponent, {
- transaction: { ...exampleData.tip, pending: true }
+ transaction: { ...exampleData.tip, pending: true },
});
export const Refund = createExample(TestedComponent, {
- transaction: exampleData.refund
+ transaction: exampleData.refund,
});
export const RefundError = createExample(TestedComponent, {
transaction: {
...exampleData.refund,
- error: transactionError
+ error: transactionError,
},
});
export const RefundPending = createExample(TestedComponent, {
- transaction: { ...exampleData.refund, pending: true }
+ transaction: { ...exampleData.refund, pending: true },
});
export const RefundWithProducts = createExample(TestedComponent, {
@@ -266,11 +280,14 @@ export const RefundWithProducts = createExample(TestedComponent, {
...exampleData.refund,
info: {
...exampleData.refund.info,
- products: [{
- description: 't-shirt',
- }, {
- description: 'beer',
- }]
- }
+ products: [
+ {
+ description: "t-shirt",
+ },
+ {
+ description: "beer",
+ },
+ ],
+ },
} as TransactionRefund,
});
diff --git a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
index cf41efb59..7de6982e7 100644
--- a/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Transaction.tsx
@@ -14,27 +14,43 @@
TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
-import { AmountLike, Amounts, i18n, Transaction, TransactionType } from "@gnu-taler/taler-util";
+import {
+ AmountLike,
+ Amounts,
+ i18n,
+ Transaction,
+ TransactionType,
+} from "@gnu-taler/taler-util";
import { format } from "date-fns";
-import { JSX, VNode } from "preact";
-import { route } from 'preact-router';
+import { JSX, VNode, h } from "preact";
+import { route } from "preact-router";
import { useEffect, useState } from "preact/hooks";
import emptyImg from "../../static/img/empty.png";
import { ErrorMessage } from "../components/ErrorMessage";
import { Part } from "../components/Part";
-import { ButtonBox, ButtonBoxDestructive, ButtonPrimary, FontIcon, ListOfProducts, RowBorderGray, SmallLightText, WalletBox, WarningBox } from "../components/styled";
+import {
+ ButtonBox,
+ ButtonBoxDestructive,
+ ButtonPrimary,
+ FontIcon,
+ ListOfProducts,
+ RowBorderGray,
+ SmallLightText,
+ WalletBox,
+ WarningBox,
+} from "../components/styled";
import { Pages } from "../NavigationBar";
import * as wxApi from "../wxApi";
-export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
- const [transaction, setTransaction] = useState<
- Transaction | undefined
- >(undefined);
+export function TransactionPage({ tid }: { tid: string }): JSX.Element {
+ const [transaction, setTransaction] = useState<Transaction | undefined>(
+ undefined,
+ );
useEffect(() => {
const fetchData = async (): Promise<void> => {
const res = await wxApi.getTransactions();
- const ts = res.transactions.filter(t => t.transactionId === tid);
+ const ts = res.transactions.filter((t) => t.transactionId === tid);
if (ts.length === 1) {
setTransaction(ts[0]);
} else {
@@ -45,13 +61,22 @@ export function TransactionPage({ tid }: { tid: string; }): JSX.Element {
}, [tid]);
if (!transaction) {
- return <div><i18n.Translate>Loading ...</i18n.Translate></div>;
+ return (
+ <div>
+ <i18n.Translate>Loading ...</i18n.Translate>
+ </div>
+ );
}
- return <TransactionView
- transaction={transaction}
- onDelete={() => wxApi.deleteTransaction(tid).then(_ => history.go(-1))}
- onRetry={() => wxApi.retryTransaction(tid).then(_ => history.go(-1))}
- onBack={() => { route(Pages.history) }} />;
+ return (
+ <TransactionView
+ transaction={transaction}
+ onDelete={() => wxApi.deleteTransaction(tid).then((_) => history.go(-1))}
+ onRetry={() => wxApi.retryTransaction(tid).then((_) => history.go(-1))}
+ onBack={() => {
+ route(Pages.history);
+ }}
+ />
+ );
}
export interface WalletTransactionProps {
@@ -61,173 +86,310 @@ export interface WalletTransactionProps {
onBack: () => void;
}
-export function TransactionView({ transaction, onDelete, onRetry, onBack }: WalletTransactionProps) {
-
+export function TransactionView({
+ transaction,
+ onDelete,
+ onRetry,
+ onBack,
+}: WalletTransactionProps) {
function TransactionTemplate({ children }: { children: VNode[] }) {
- return <WalletBox>
- <section style={{ padding: 8, textAlign: 'center'}}>
- <ErrorMessage title={transaction?.error?.hint} />
- {transaction.pending && <WarningBox>This transaction is not completed</WarningBox>}
- </section>
- <section>
- <div style={{ textAlign: 'center' }}>
- {children}
- </div>
- </section>
- <footer>
- <ButtonBox onClick={onBack}><i18n.Translate> <FontIcon>&#x2190;</FontIcon> </i18n.Translate></ButtonBox>
- <div>
- {transaction?.error ? <ButtonPrimary onClick={onRetry}><i18n.Translate>retry</i18n.Translate></ButtonPrimary> : null}
- <ButtonBoxDestructive onClick={onDelete}><i18n.Translate>&#x1F5D1;</i18n.Translate></ButtonBoxDestructive>
- </div>
- </footer>
- </WalletBox>
+ return (
+ <WalletBox>
+ <section style={{ padding: 8, textAlign: "center" }}>
+ <ErrorMessage title={transaction?.error?.hint} />
+ {transaction.pending && (
+ <WarningBox>This transaction is not completed</WarningBox>
+ )}
+ </section>
+ <section>
+ <div style={{ textAlign: "center" }}>{children}</div>
+ </section>
+ <footer>
+ <ButtonBox onClick={onBack}>
+ <i18n.Translate>
+ {" "}
+ <FontIcon>&#x2190;</FontIcon>{" "}
+ </i18n.Translate>
+ </ButtonBox>
+ <div>
+ {transaction?.error ? (
+ <ButtonPrimary onClick={onRetry}>
+ <i18n.Translate>retry</i18n.Translate>
+ </ButtonPrimary>
+ ) : null}
+ <ButtonBoxDestructive onClick={onDelete}>
+ <i18n.Translate>&#x1F5D1;</i18n.Translate>
+ </ButtonBoxDestructive>
+ </div>
+ </footer>
+ </WalletBox>
+ );
}
function amountToString(text: AmountLike) {
- const aj = Amounts.jsonifyAmount(text)
- const amount = Amounts.stringifyValue(aj)
- return `${amount} ${aj.currency}`
+ const aj = Amounts.jsonifyAmount(text);
+ const amount = Amounts.stringifyValue(aj);
+ return `${amount} ${aj.currency}`;
}
-
if (transaction.type === TransactionType.Withdrawal) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Withdrawal</h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part title="Total withdrawn" text={amountToString(transaction.amountEffective)} kind='positive' />
- <Part title="Chosen amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part title="Exchange fee" text={amountToString(fee)} kind='negative' />
- <Part title="Exchange" text={new URL(transaction.exchangeBaseUrl).hostname} kind='neutral' />
- </TransactionTemplate>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Withdrawal</h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ title="Total withdrawn"
+ text={amountToString(transaction.amountEffective)}
+ kind="positive"
+ />
+ <Part
+ title="Chosen amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part title="Exchange fee" text={amountToString(fee)} kind="negative" />
+ <Part
+ title="Exchange"
+ text={new URL(transaction.exchangeBaseUrl).hostname}
+ kind="neutral"
+ />
+ </TransactionTemplate>
+ );
}
- const showLargePic = () => {
-
- }
+ const showLargePic = () => {};
if (transaction.type === TransactionType.Payment) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountEffective),
Amounts.parseOrThrow(transaction.amountRaw),
- ).amount
-
- return <TransactionTemplate>
- <h2>Payment </h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part big title="Total paid" text={amountToString(transaction.amountEffective)} kind='negative' />
- <Part big title="Purchase amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part big title="Fee" text={amountToString(fee)} kind='negative' />
- <Part title="Merchant" text={transaction.info.merchant.name} kind='neutral' />
- <Part title="Purchase" text={transaction.info.summary} kind='neutral' />
- <Part title="Receipt" text={`#${transaction.info.orderId}`} kind='neutral' />
+ ).amount;
- <div>
- {transaction.info.products && transaction.info.products.length > 0 &&
- <ListOfProducts>
- {transaction.info.products.map((p, k) => <RowBorderGray key={k}>
- <a href="#" onClick={showLargePic}>
- <img src={p.image ? p.image : emptyImg} />
- </a>
- <div>
- {p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
- <div>{p.description}</div>
- </div>
- </RowBorderGray>)}
- </ListOfProducts>
- }
- </div>
- </TransactionTemplate>
+ return (
+ <TransactionTemplate>
+ <h2>Payment </h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ big
+ title="Total paid"
+ text={amountToString(transaction.amountEffective)}
+ kind="negative"
+ />
+ <Part
+ big
+ title="Purchase amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part big title="Fee" text={amountToString(fee)} kind="negative" />
+ <Part
+ title="Merchant"
+ text={transaction.info.merchant.name}
+ kind="neutral"
+ />
+ <Part title="Purchase" text={transaction.info.summary} kind="neutral" />
+ <Part
+ title="Receipt"
+ text={`#${transaction.info.orderId}`}
+ kind="neutral"
+ />
+
+ <div>
+ {transaction.info.products && transaction.info.products.length > 0 && (
+ <ListOfProducts>
+ {transaction.info.products.map((p, k) => (
+ <RowBorderGray key={k}>
+ <a href="#" onClick={showLargePic}>
+ <img src={p.image ? p.image : emptyImg} />
+ </a>
+ <div>
+ {p.quantity && p.quantity > 0 && (
+ <SmallLightText>
+ x {p.quantity} {p.unit}
+ </SmallLightText>
+ )}
+ <div>{p.description}</div>
+ </div>
+ </RowBorderGray>
+ ))}
+ </ListOfProducts>
+ )}
+ </div>
+ </TransactionTemplate>
+ );
}
if (transaction.type === TransactionType.Deposit) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Deposit </h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part big title="Total deposit" text={amountToString(transaction.amountEffective)} kind='negative' />
- <Part big title="Purchase amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part big title="Fee" text={amountToString(fee)} kind='negative' />
- </TransactionTemplate>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Deposit </h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ big
+ title="Total deposit"
+ text={amountToString(transaction.amountEffective)}
+ kind="negative"
+ />
+ <Part
+ big
+ title="Purchase amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part big title="Fee" text={amountToString(fee)} kind="negative" />
+ </TransactionTemplate>
+ );
}
if (transaction.type === TransactionType.Refresh) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Refresh</h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part big title="Total refresh" text={amountToString(transaction.amountEffective)} kind='negative' />
- <Part big title="Refresh amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part big title="Fee" text={amountToString(fee)} kind='negative' />
- </TransactionTemplate>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Refresh</h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ big
+ title="Total refresh"
+ text={amountToString(transaction.amountEffective)}
+ kind="negative"
+ />
+ <Part
+ big
+ title="Refresh amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part big title="Fee" text={amountToString(fee)} kind="negative" />
+ </TransactionTemplate>
+ );
}
if (transaction.type === TransactionType.Tip) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Tip</h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part big title="Total tip" text={amountToString(transaction.amountEffective)} kind='positive' />
- <Part big title="Received amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part big title="Fee" text={amountToString(fee)} kind='negative' />
- </TransactionTemplate>
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Tip</h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ big
+ title="Total tip"
+ text={amountToString(transaction.amountEffective)}
+ kind="positive"
+ />
+ <Part
+ big
+ title="Received amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part big title="Fee" text={amountToString(fee)} kind="negative" />
+ </TransactionTemplate>
+ );
}
if (transaction.type === TransactionType.Refund) {
const fee = Amounts.sub(
Amounts.parseOrThrow(transaction.amountRaw),
Amounts.parseOrThrow(transaction.amountEffective),
- ).amount
- return <TransactionTemplate>
- <h2>Refund</h2>
- <div>{transaction.timestamp.t_ms === 'never' ? 'never' : format(transaction.timestamp.t_ms, 'dd MMMM yyyy, HH:mm')}</div>
- <br />
- <Part big title="Total refund" text={amountToString(transaction.amountEffective)} kind='positive' />
- <Part big title="Refund amount" text={amountToString(transaction.amountRaw)} kind='neutral' />
- <Part big title="Fee" text={amountToString(fee)} kind='negative' />
- <Part title="Merchant" text={transaction.info.merchant.name} kind='neutral' />
- <Part title="Purchase" text={transaction.info.summary} kind='neutral' />
- <Part title="Receipt" text={`#${transaction.info.orderId}`} kind='neutral' />
-
- <p>
- {transaction.info.summary}
- </p>
- <div>
- {transaction.info.products && transaction.info.products.length > 0 &&
- <ListOfProducts>
- {transaction.info.products.map((p, k) => <RowBorderGray key={k}>
- <a href="#" onClick={showLargePic}>
- <img src={p.image ? p.image : emptyImg} />
- </a>
- <div>
- {p.quantity && p.quantity > 0 && <SmallLightText>x {p.quantity} {p.unit}</SmallLightText>}
- <div>{p.description}</div>
- </div>
- </RowBorderGray>)}
- </ListOfProducts>
- }
- </div>
- </TransactionTemplate>
- }
+ ).amount;
+ return (
+ <TransactionTemplate>
+ <h2>Refund</h2>
+ <div>
+ {transaction.timestamp.t_ms === "never"
+ ? "never"
+ : format(transaction.timestamp.t_ms, "dd MMMM yyyy, HH:mm")}
+ </div>
+ <br />
+ <Part
+ big
+ title="Total refund"
+ text={amountToString(transaction.amountEffective)}
+ kind="positive"
+ />
+ <Part
+ big
+ title="Refund amount"
+ text={amountToString(transaction.amountRaw)}
+ kind="neutral"
+ />
+ <Part big title="Fee" text={amountToString(fee)} kind="negative" />
+ <Part
+ title="Merchant"
+ text={transaction.info.merchant.name}
+ kind="neutral"
+ />
+ <Part title="Purchase" text={transaction.info.summary} kind="neutral" />
+ <Part
+ title="Receipt"
+ text={`#${transaction.info.orderId}`}
+ kind="neutral"
+ />
+ <p>{transaction.info.summary}</p>
+ <div>
+ {transaction.info.products && transaction.info.products.length > 0 && (
+ <ListOfProducts>
+ {transaction.info.products.map((p, k) => (
+ <RowBorderGray key={k}>
+ <a href="#" onClick={showLargePic}>
+ <img src={p.image ? p.image : emptyImg} />
+ </a>
+ <div>
+ {p.quantity && p.quantity > 0 && (
+ <SmallLightText>
+ x {p.quantity} {p.unit}
+ </SmallLightText>
+ )}
+ <div>{p.description}</div>
+ </div>
+ </RowBorderGray>
+ ))}
+ </ListOfProducts>
+ )}
+ </div>
+ </TransactionTemplate>
+ );
+ }
- return <div></div>
+ return <div></div>;
}
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
index 6579450b3..7e6588fac 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.stories.tsx
@@ -15,16 +15,15 @@
*/
/**
-*
-* @author Sebastian Javier Marchano (sebasjm)
-*/
-
-import { createExample } from '../test-utils';
-import { View as TestedComponent } from './Welcome';
+ *
+ * @author Sebastian Javier Marchano (sebasjm)
+ */
+import { createExample } from "../test-utils";
+import { View as TestedComponent } from "./Welcome";
export default {
- title: 'wallet/welcome',
+ title: "wallet/welcome",
component: TestedComponent,
};
@@ -32,11 +31,11 @@ export const Normal = createExample(TestedComponent, {
permissionsEnabled: true,
diagnostics: {
errors: [],
- walletManifestVersion: '1.0',
- walletManifestDisplayVersion: '1.0',
+ walletManifestVersion: "1.0",
+ walletManifestDisplayVersion: "1.0",
firefoxIdbProblem: false,
dbOutdated: false,
- }
+ },
});
export const TimedoutDiagnostics = createExample(TestedComponent, {
@@ -47,4 +46,3 @@ export const TimedoutDiagnostics = createExample(TestedComponent, {
export const RunningDiagnostics = createExample(TestedComponent, {
permissionsEnabled: false,
});
-
diff --git a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
index d11070d9a..0b8e5c609 100644
--- a/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Welcome.tsx
@@ -27,43 +27,55 @@ import { Diagnostics } from "../components/Diagnostics";
import { WalletBox } from "../components/styled";
import { useDiagnostics } from "../hooks/useDiagnostics";
import { WalletDiagnostics } from "@gnu-taler/taler-util";
-import { h } from 'preact';
+import { h } from "preact";
export function WelcomePage() {
- const [permissionsEnabled, togglePermissions] = useExtendedPermissions()
- const [diagnostics, timedOut] = useDiagnostics()
- return <View
- permissionsEnabled={permissionsEnabled} togglePermissions={togglePermissions}
- diagnostics={diagnostics} timedOut={timedOut}
- />
+ const [permissionsEnabled, togglePermissions] = useExtendedPermissions();
+ const [diagnostics, timedOut] = useDiagnostics();
+ return (
+ <View
+ permissionsEnabled={permissionsEnabled}
+ togglePermissions={togglePermissions}
+ diagnostics={diagnostics}
+ timedOut={timedOut}
+ />
+ );
}
export interface ViewProps {
- permissionsEnabled: boolean,
- togglePermissions: () => void,
- diagnostics: WalletDiagnostics | undefined,
- timedOut: boolean,
+ permissionsEnabled: boolean;
+ togglePermissions: () => void;
+ diagnostics: WalletDiagnostics | undefined;
+ timedOut: boolean;
}
-export function View({ permissionsEnabled, togglePermissions, diagnostics, timedOut }: ViewProps): JSX.Element {
- return (<WalletBox>
- <h1>Browser Extension Installed!</h1>
- <div>
- <p>Thank you for installing the wallet.</p>
- <Diagnostics diagnostics={diagnostics} timedOut={timedOut} />
- <h2>Permissions</h2>
- <Checkbox label="Automatically open wallet based on page content"
- name="perm"
- description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
- enabled={permissionsEnabled} onToggle={togglePermissions}
- />
- <h2>Next Steps</h2>
- <a href="https://demo.taler.net/" style={{ display: "block" }}>
- Try the demo »
- </a>
- <a href="https://demo.taler.net/" style={{ display: "block" }}>
- Learn how to top up your wallet balance »
- </a>
- </div>
- </WalletBox>
+export function View({
+ permissionsEnabled,
+ togglePermissions,
+ diagnostics,
+ timedOut,
+}: ViewProps): JSX.Element {
+ return (
+ <WalletBox>
+ <h1>Browser Extension Installed!</h1>
+ <div>
+ <p>Thank you for installing the wallet.</p>
+ <Diagnostics diagnostics={diagnostics} timedOut={timedOut} />
+ <h2>Permissions</h2>
+ <Checkbox
+ label="Automatically open wallet based on page content"
+ name="perm"
+ description="(Enabling this option below will make using the wallet faster, but requires more permissions from your browser.)"
+ enabled={permissionsEnabled}
+ onToggle={togglePermissions}
+ />
+ <h2>Next Steps</h2>
+ <a href="https://demo.taler.net/" style={{ display: "block" }}>
+ Try the demo »
+ </a>
+ <a href="https://demo.taler.net/" style={{ display: "block" }}>
+ Learn how to top up your wallet balance »
+ </a>
+ </div>
+ </WalletBox>
);
}
diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
index 023ee94c5..f097d58b5 100644
--- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
+++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx
@@ -21,7 +21,7 @@
*/
import { setupI18n } from "@gnu-taler/taler-util";
-import { createHashHistory } from 'history';
+import { createHashHistory } from "history";
import { Fragment, h, render } from "preact";
import Router, { route, Route } from "preact-router";
import { useEffect } from "preact/hooks";
@@ -29,22 +29,19 @@ import { LogoHeader } from "./components/LogoHeader";
import { DevContextProvider } from "./context/devContext";
import { PayPage } from "./cta/Pay";
import { RefundPage } from "./cta/Refund";
-import { TipPage } from './cta/Tip';
+import { TipPage } from "./cta/Tip";
import { WithdrawPage } from "./cta/Withdraw";
import { strings } from "./i18n/strings";
-import {
- Pages, WalletNavBar
-} from "./NavigationBar";
+import { Pages, WalletNavBar } from "./NavigationBar";
import { BalancePage } from "./wallet/BalancePage";
import { HistoryPage } from "./wallet/History";
import { SettingsPage } from "./wallet/Settings";
-import { TransactionPage } from './wallet/Transaction';
+import { TransactionPage } from "./wallet/Transaction";
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 {
try {
const container = document.getElementById("container");
@@ -69,51 +66,86 @@ if (document.readyState === "loading") {
}
function withLogoAndNavBar(Component: any) {
- return (props: any) => <Fragment>
- <LogoHeader />
- <WalletNavBar />
- <Component {...props} />
- </Fragment>
+ return (props: any) => (
+ <Fragment>
+ <LogoHeader />
+ <WalletNavBar />
+ <Component {...props} />
+ </Fragment>
+ );
}
function Application() {
- return <div>
- <DevContextProvider>
- <Router history={createHashHistory()} >
-
- <Route path={Pages.welcome} component={withLogoAndNavBar(WelcomePage)} />
-
- <Route path={Pages.history} component={withLogoAndNavBar(HistoryPage)} />
- <Route path={Pages.transaction} component={withLogoAndNavBar(TransactionPage)} />
- <Route path={Pages.balance} component={withLogoAndNavBar(BalancePage)}
- goToWalletManualWithdraw={() => route(Pages.manual_withdraw)}
- />
- <Route path={Pages.settings} component={withLogoAndNavBar(SettingsPage)} />
- <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.payback} 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 */}
- <Route path={Pages.pay} component={PayPage} />
- <Route path={Pages.refund} component={RefundPage} />
- <Route path={Pages.tips} component={TipPage} />
- <Route path={Pages.withdraw} component={WithdrawPage} />
-
- <Route default component={Redirect} to={Pages.history} />
- </Router>
- </DevContextProvider>
- </div>
+ return (
+ <div>
+ <DevContextProvider>
+ <Router history={createHashHistory()}>
+ <Route
+ path={Pages.welcome}
+ component={withLogoAndNavBar(WelcomePage)}
+ />
+
+ <Route
+ path={Pages.history}
+ component={withLogoAndNavBar(HistoryPage)}
+ />
+ <Route
+ path={Pages.transaction}
+ component={withLogoAndNavBar(TransactionPage)}
+ />
+ <Route
+ path={Pages.balance}
+ component={withLogoAndNavBar(BalancePage)}
+ goToWalletManualWithdraw={() => route(Pages.manual_withdraw)}
+ />
+ <Route
+ path={Pages.settings}
+ component={withLogoAndNavBar(SettingsPage)}
+ />
+ <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.payback}
+ 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 */}
+ <Route path={Pages.pay} component={PayPage} />
+ <Route path={Pages.refund} component={RefundPage} />
+ <Route path={Pages.tips} component={TipPage} />
+ <Route path={Pages.withdraw} component={WithdrawPage} />
+
+ <Route default component={Redirect} to={Pages.history} />
+ </Router>
+ </DevContextProvider>
+ </div>
+ );
}
function Redirect({ to }: { to: string }): null {
useEffect(() => {
- route(to, true)
- })
- return null
+ route(to, true);
+ });
+ return null;
}
diff --git a/packages/taler-wallet-webextension/src/wxApi.ts b/packages/taler-wallet-webextension/src/wxApi.ts
index 92597cbd2..90cfd3ed6 100644
--- a/packages/taler-wallet-webextension/src/wxApi.ts
+++ b/packages/taler-wallet-webextension/src/wxApi.ts
@@ -47,7 +47,12 @@ import {
AddExchangeRequest,
GetExchangeTosResult,
} 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 { ExchangeWithdrawDetails } from "@gnu-taler/taler-wallet-core/src/operations/withdraw";
@@ -149,78 +154,89 @@ interface CurrencyInfo {
pub: string;
}
interface ListOfKnownCurrencies {
- auditors: CurrencyInfo[],
- exchanges: CurrencyInfo[],
+ auditors: CurrencyInfo[];
+ exchanges: CurrencyInfo[];
}
/**
* Get a list of currencies from known auditors and exchanges
*/
export function listKnownCurrencies(): Promise<ListOfKnownCurrencies> {
- return callBackend("listCurrencies", {}).then(result => {
- console.log("result list", result)
- const auditors = result.trustedAuditors.map((a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.auditorBaseUrl,
- pub: a.auditorPub,
- }))
- const exchanges = result.trustedExchanges.map((a: Record<string, string>) => ({
- name: a.currency,
- baseUrl: a.exchangeBaseUrl,
- pub: a.exchangeMasterPub,
- }))
- return { auditors, exchanges }
+ return callBackend("listCurrencies", {}).then((result) => {
+ console.log("result list", result);
+ const auditors = result.trustedAuditors.map(
+ (a: Record<string, string>) => ({
+ name: a.currency,
+ baseUrl: a.auditorBaseUrl,
+ pub: a.auditorPub,
+ }),
+ );
+ const exchanges = result.trustedExchanges.map(
+ (a: Record<string, string>) => ({
+ name: a.currency,
+ baseUrl: a.exchangeBaseUrl,
+ pub: a.exchangeMasterPub,
+ }),
+ );
+ return { auditors, exchanges };
});
}
export function listExchanges(): Promise<ExchangesListRespose> {
- return callBackend("listExchanges", {})
+ return callBackend("listExchanges", {});
}
/**
* Get information about the current state of wallet backups.
*/
export function getBackupInfo(): Promise<BackupInfo> {
- return callBackend("getBackupInfo", {})
+ return callBackend("getBackupInfo", {});
}
/**
* Add a backup provider and activate it
*/
-export function addBackupProvider(backupProviderBaseUrl: string, name: string): Promise<void> {
+export function addBackupProvider(
+ backupProviderBaseUrl: string,
+ name: string,
+): Promise<void> {
return callBackend("addBackupProvider", {
- backupProviderBaseUrl, activate: true, name
- } as AddBackupProviderRequest)
+ backupProviderBaseUrl,
+ activate: true,
+ name,
+ } as AddBackupProviderRequest);
}
export function setWalletDeviceId(walletDeviceId: string): Promise<void> {
return callBackend("setWalletDeviceId", {
- walletDeviceId
- } as SetWalletDeviceIdRequest)
+ walletDeviceId,
+ } as SetWalletDeviceIdRequest);
}
export function syncAllProviders(): Promise<void> {
- return callBackend("runBackupCycle", {})
+ return callBackend("runBackupCycle", {});
}
export function syncOneProvider(url: string): Promise<void> {
- return callBackend("runBackupCycle", { providers: [url] })
+ return callBackend("runBackupCycle", { providers: [url] });
}
export function removeProvider(url: string): Promise<void> {
- return callBackend("removeBackupProvider", { provider: url } as RemoveBackupProviderRequest)
+ return callBackend("removeBackupProvider", {
+ provider: url,
+ } as RemoveBackupProviderRequest);
}
export function extendedProvider(url: string): Promise<void> {
- return callBackend("extendBackupProvider", { provider: url })
+ return callBackend("extendBackupProvider", { provider: url });
}
/**
* Retry a transaction
- * @param transactionId
- * @returns
+ * @param transactionId
+ * @returns
*/
export function retryTransaction(transactionId: string): Promise<void> {
return callBackend("retryTransaction", {
- transactionId
+ transactionId,
} as RetryTransactionRequest);
}
@@ -229,7 +245,7 @@ export function retryTransaction(transactionId: string): Promise<void> {
*/
export function deleteTransaction(transactionId: string): Promise<void> {
return callBackend("deleteTransaction", {
- transactionId
+ transactionId,
} as DeleteTransactionRequest);
}
@@ -264,29 +280,30 @@ export function acceptWithdrawal(
/**
* Create a reserve into the exchange that expect the amount indicated
- * @param exchangeBaseUrl
- * @param amount
- * @returns
+ * @param exchangeBaseUrl
+ * @param amount
+ * @returns
*/
export function acceptManualWithdrawal(
exchangeBaseUrl: string,
amount: string,
): Promise<AcceptManualWithdrawalResult> {
return callBackend("acceptManualWithdrawal", {
- amount, exchangeBaseUrl
+ amount,
+ exchangeBaseUrl,
});
}
export function setExchangeTosAccepted(
exchangeBaseUrl: string,
- etag: string | undefined
+ etag: string | undefined,
): Promise<void> {
return callBackend("setExchangeTosAccepted", {
- exchangeBaseUrl, etag
- } as AcceptExchangeTosRequest)
+ exchangeBaseUrl,
+ etag,
+ } as AcceptExchangeTosRequest);
}
-
/**
* Get diagnostics information
*/
@@ -319,7 +336,6 @@ export function getWithdrawalDetailsForUri(
return callBackend("getWithdrawalDetailsForUri", req);
}
-
/**
* Get diagnostics information
*/
@@ -333,17 +349,15 @@ export function getExchangeTos(
acceptedFormat: string[],
): Promise<GetExchangeTosResult> {
return callBackend("getExchangeTos", {
- exchangeBaseUrl, acceptedFormat
+ exchangeBaseUrl,
+ acceptedFormat,
});
}
-export function addExchange(
- req: AddExchangeRequest,
-): Promise<void> {
+export function addExchange(req: AddExchangeRequest): Promise<void> {
return callBackend("addExchange", req);
}
-
export function prepareTip(req: PrepareTipRequest): Promise<PrepareTipResult> {
return callBackend("prepareTip", req);
}
diff --git a/packages/taler-wallet-webextension/tsconfig.json b/packages/taler-wallet-webextension/tsconfig.json
index cff3d8857..25920a120 100644
--- a/packages/taler-wallet-webextension/tsconfig.json
+++ b/packages/taler-wallet-webextension/tsconfig.json
@@ -1,9 +1,13 @@
{
"compilerOptions": {
"composite": true,
- "lib": ["es6", "DOM"],
- "jsx": "react-jsx",
- "jsxImportSource": "preact",
+ "lib": [
+ "es6",
+ "DOM"
+ ],
+ "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
+ "jsxFactory": "h", /* Specify the JSX factory function to use when targeting react JSX emit, e.g. React.createElement or h. */
+ "jsxFragmentFactory": "Fragment", // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-0.html#custom-jsx-factories
"moduleResolution": "Node",
"module": "ESNext",
"target": "ES6",
@@ -16,7 +20,9 @@
"esModuleInterop": true,
"importHelpers": true,
"rootDir": "./src",
- "typeRoots": ["./node_modules/@types"]
+ "typeRoots": [
+ "./node_modules/@types"
+ ]
},
"references": [
{
@@ -26,5 +32,7 @@
"path": "../taler-util/"
}
],
- "include": ["src/**/*"]
-}
+ "include": [
+ "src/**/*"
+ ]
+} \ No newline at end of file