diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src/popup')
6 files changed, 238 insertions, 75 deletions
diff --git a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx index a0655d379..382f9b549 100644 --- a/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx +++ b/packages/taler-wallet-webextension/src/popup/Balance.stories.tsx @@ -35,14 +35,15 @@ export const NotYetLoaded = createExample(TestedComponent, { export const GotError = createExample(TestedComponent, { balance: { - error: true + hasError: true, + message: 'Network error' }, Linker: NullLink, }); export const EmptyBalance = createExample(TestedComponent, { balance: { - error: false, + hasError: false, response: { balances: [] }, @@ -52,7 +53,7 @@ export const EmptyBalance = createExample(TestedComponent, { export const SomeCoins = createExample(TestedComponent, { balance: { - error: false, + hasError: false, response: { balances: [{ available: 'USD:10.5', @@ -68,7 +69,7 @@ export const SomeCoins = createExample(TestedComponent, { export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, { balance: { - error: false, + hasError: false, response: { balances: [{ available: 'USD:2.23', @@ -82,22 +83,135 @@ export const SomeCoinsAndIncomingMoney = createExample(TestedComponent, { Linker: NullLink, }); +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 + }] + }, + }, + Linker: NullLink, +}); + +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 + }] + }, + }, + Linker: NullLink, +}); + export const SomeCoinsInTwoCurrencies = createExample(TestedComponent, { balance: { - error: false, + hasError: false, response: { balances: [{ available: 'USD:2', hasPendingTransactions: false, - pendingIncoming: 'USD:5', + pendingIncoming: 'USD:5.1', pendingOutgoing: 'USD:0', requiresUserInput: false },{ available: 'EUR:4', hasPendingTransactions: false, - pendingIncoming: 'EUR:5', + pendingIncoming: 'EUR:0', + pendingOutgoing: 'EUR:3.01', + requiresUserInput: false + }] + }, + }, + Linker: NullLink, +}); + +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 + }] + }, + }, + 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 }] }, }, diff --git a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx index e3bada8d4..8e5c5c42e 100644 --- a/packages/taler-wallet-webextension/src/popup/BalancePage.tsx +++ b/packages/taler-wallet-webextension/src/popup/BalancePage.tsx @@ -19,8 +19,9 @@ import { Balance, BalancesResponse, i18n } from "@gnu-taler/taler-util"; -import { JSX, h } from "preact"; -import { PopupBox, Centered, ButtonPrimary } from "../components/styled/index"; +import { JSX, h, Fragment } from "preact"; +import { ErrorMessage } from "../components/ErrorMessage"; +import { PopupBox, Centered, ButtonPrimary, ErrorBox, Middle } from "../components/styled/index"; import { BalancesHook, useBalances } from "../hooks/useBalances"; import { PageLink, renderAmount } from "../renderHtml"; @@ -34,34 +35,6 @@ export interface BalanceViewProps { Linker: typeof PageLink; goToWalletManualWithdraw: () => void; } -export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) { - if (!balance) { - return <span /> - } - - if (balance.error) { - return ( - <div> - <p>{i18n.str`Error: could not retrieve balance information.`}</p> - <p> - Click <Linker pageName="welcome">here</Linker> for help and - 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> - ) - } - return <ShowBalances wallet={balance.response} - onWithdraw={goToWalletManualWithdraw} - /> -} function formatPending(entry: Balance): JSX.Element { let incoming: JSX.Element | undefined; @@ -74,11 +47,20 @@ function formatPending(entry: Balance): JSX.Element { if (!Amounts.isZero(pendingIncoming)) { incoming = ( <span><i18n.Translate> - <span style={{ color: "darkgreen" }}> + <span style={{ color: "darkgreen" }} title="incoming amount"> {"+"} {renderAmount(entry.pendingIncoming)} </span>{" "} - incoming + </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> ); } @@ -89,36 +71,85 @@ function formatPending(entry: Balance): JSX.Element { } if (l.length === 1) { - return <span>({l})</span>; + return <span>{l}</span>; } return ( <span> - ({l[0]}, {l[1]}) + {l[0]}, {l[1]} </span> ); } -function ShowBalances({ wallet, onWithdraw }: { wallet: BalancesResponse, onWithdraw: () => void }) { - return <PopupBox> - <section> - <Centered>{wallet.balances.map((entry) => { +export function BalanceView({ balance, Linker, goToWalletManualWithdraw }: BalanceViewProps) { + + function Content() { + if (!balance) { + return <span /> + } + + if (balance.hasError) { + 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 data-centered> + <table style={{width:'100%'}}>{balance.response.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> + // 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> ); - })}</Centered> + })}</table> </section> + } + + return <PopupBox> + {/* <section> */} + <Content /> + {/* </section> */} <footer> <div /> - <ButtonPrimary onClick={onWithdraw} >Withdraw</ButtonPrimary> + <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 3968b0191..ccc747466 100644 --- a/packages/taler-wallet-webextension/src/popup/Debug.tsx +++ b/packages/taler-wallet-webextension/src/popup/Debug.tsx @@ -28,7 +28,6 @@ export function DeveloperPage(props: any): JSX.Element { <button onClick={openExtensionPage("/static/popup.html")}>wallet tab</button> <br /> <button onClick={confirmReset}>reset</button> - <button onClick={reload}>reload chrome extension</button> <Diagnostics diagnostics={status} timedOut={timedOut} /> </div> ); diff --git a/packages/taler-wallet-webextension/src/popup/History.stories.tsx b/packages/taler-wallet-webextension/src/popup/History.stories.tsx index ca9f545fe..daa263a81 100644 --- a/packages/taler-wallet-webextension/src/popup/History.stories.tsx +++ b/packages/taler-wallet-webextension/src/popup/History.stories.tsx @@ -105,7 +105,7 @@ const exampleData = { } as TransactionRefund, } -export const Empty = createExample(TestedComponent, { +export const EmptyWithBalance = createExample(TestedComponent, { list: [], balances: [{ available: 'TESTKUDOS:10', @@ -116,6 +116,10 @@ export const Empty = createExample(TestedComponent, { }] }); +export const EmptyWithNoBalance = createExample(TestedComponent, { + list: [], + balances: [] +}); export const One = createExample(TestedComponent, { list: [exampleData.withdraw], diff --git a/packages/taler-wallet-webextension/src/popup/History.tsx b/packages/taler-wallet-webextension/src/popup/History.tsx index 77d603886..1447da9b0 100644 --- a/packages/taler-wallet-webextension/src/popup/History.tsx +++ b/packages/taler-wallet-webextension/src/popup/History.tsx @@ -14,7 +14,7 @@ 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, i18n, Transaction, TransactionsResponse } from "@gnu-taler/taler-util"; import { h, JSX } from "preact"; import { useEffect, useState } from "preact/hooks"; import { PopupBox } from "../components/styled"; @@ -28,7 +28,7 @@ export function HistoryPage(props: any): JSX.Element { TransactionsResponse | undefined >(undefined); const balance = useBalances() - const balanceWithoutError = balance?.error ? [] : (balance?.response.balances || []) + const balanceWithoutError = balance?.hasError ? [] : (balance?.response.balances || []) useEffect(() => { const fetchData = async (): Promise<void> => { @@ -64,16 +64,24 @@ export function HistoryView({ list, balances }: { list: Transaction[], balances: Balance: <span>{amountToString(balances[0].available)}</span> </div>} </header>} - <section> - {list.slice(0, 3).map((tx, i) => ( - <TransactionItem key={i} tx={tx} multiCurrency={multiCurrency}/> - ))} - </section> + {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' }}> - <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> + {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/Settings.tsx b/packages/taler-wallet-webextension/src/popup/Settings.tsx index 52e72ee2f..8595c87ff 100644 --- a/packages/taler-wallet-webextension/src/popup/Settings.tsx +++ b/packages/taler-wallet-webextension/src/popup/Settings.tsx @@ -20,6 +20,7 @@ import { VNode, h } from "preact"; import { Checkbox } from "../components/Checkbox"; import { EditableText } from "../components/EditableText"; import { SelectList } from "../components/SelectList"; +import { PopupBox } from "../components/styled"; import { useDevContext } from "../context/devContext"; import { useBackupDeviceName } from "../hooks/useBackupDeviceName"; import { useExtendedPermissions } from "../hooks/useExtendedPermissions"; @@ -67,10 +68,10 @@ const names: LangsNames = { export function SettingsView({ lang, changeLang, deviceName, setDeviceName, permissionsEnabled, togglePermissions, developerMode, toggleDeveloperMode }: ViewProps): VNode { return ( - <div> - <section style={{ height: 300, overflow: 'auto' }}> - <h2><i18n.Translate>Wallet</i18n.Translate></h2> - <SelectList + <PopupBox> + <section> + {/* <h2><i18n.Translate>Wallet</i18n.Translate></h2> */} + {/* <SelectList value={lang} onChange={changeLang} name="lang" @@ -84,7 +85,7 @@ export function SettingsView({ lang, changeLang, deviceName, setDeviceName, perm name="device-id" 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" name="perm" @@ -98,6 +99,12 @@ export function SettingsView({ lang, changeLang, deviceName, setDeviceName, perm enabled={developerMode} onToggle={toggleDeveloperMode} /> </section> - </div> + <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> + </footer> + </PopupBox> ) }
\ No newline at end of file |