From 882d6b3710f82d85b2129f09c63f9db45985ef64 Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 24 Jan 2022 14:12:12 -0300 Subject: last activity -> pending; fix downloadTos --- packages/taler-util/src/amounts.ts | 6 +- .../taler-wallet-core/src/operations/exchanges.ts | 84 ++++++++++------ packages/taler-wallet-core/src/wallet.ts | 35 ++++++- .../src/NavigationBar.tsx | 7 +- .../src/components/TransactionItem.tsx | 26 ++--- .../src/components/styled/index.tsx | 13 +-- .../src/popupEntryPoint.tsx | 4 +- .../src/wallet/History.stories.tsx | 44 +++++++++ .../src/wallet/History.tsx | 107 ++++++++++++--------- .../src/wallet/LastActivityPage.stories.tsx | 33 ------- .../src/wallet/LastActivityPage.tsx | 35 ------- .../src/wallet/PendingPage.stories.tsx | 33 +++++++ .../src/wallet/PendingPage.tsx | 35 +++++++ .../src/walletEntryPoint.tsx | 31 +++--- 14 files changed, 293 insertions(+), 200 deletions(-) delete mode 100644 packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx delete mode 100644 packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx create mode 100644 packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx create mode 100644 packages/taler-wallet-webextension/src/wallet/PendingPage.tsx diff --git a/packages/taler-util/src/amounts.ts b/packages/taler-util/src/amounts.ts index cd74cda35..d389e3ed3 100644 --- a/packages/taler-util/src/amounts.ts +++ b/packages/taler-util/src/amounts.ts @@ -431,7 +431,9 @@ export class Amounts { } } - const currencyFormatter = new Intl.NumberFormat("en-US"); - return currencyFormatter.format(Number(s)); + const currencyFormatter = new Intl.NumberFormat("en-US", { + minimumFractionDigits: minFractional, + }); + return currencyFormatter.format(s as any); } } diff --git a/packages/taler-wallet-core/src/operations/exchanges.ts b/packages/taler-wallet-core/src/operations/exchanges.ts index d73d593e8..87200c2f9 100644 --- a/packages/taler-wallet-core/src/operations/exchanges.ts +++ b/packages/taler-wallet-core/src/operations/exchanges.ts @@ -138,7 +138,7 @@ async function handleExchangeUpdateError( } } -function getExchangeRequestTimeout(e: ExchangeRecord): Duration { +export function getExchangeRequestTimeout(): Duration { return { d_ms: 5000 }; } @@ -199,6 +199,27 @@ getExchangeDetails.makeContext = (db: DbAccess) => exchangeDetails: x.exchangeDetails, })); +export async function updateExchangeTermsOfService( + ws: InternalWalletState, + exchangeBaseUrl: string, + tos: ExchangeTosDownloadResult, +): Promise { + await ws.db + .mktx((x) => ({ + exchanges: x.exchanges, + exchangeDetails: x.exchangeDetails, + })) + .runReadWrite(async (tx) => { + const d = await getExchangeDetails(tx, exchangeBaseUrl); + if (d) { + d.termsOfServiceText = tos.tosText; + d.termsOfServiceContentType = tos.tosContentType; + d.termsOfServiceLastEtag = tos.tosEtag; + await tx.exchangeDetails.put(d); + } + }); +} + export async function acceptExchangeTermsOfService( ws: InternalWalletState, exchangeBaseUrl: string, @@ -434,6 +455,36 @@ async function downloadKeysInfo( }; } +export async function downloadTosFromAcceptedFormat( + ws: InternalWalletState, + baseUrl: string, + timeout: Duration, + acceptedFormat?: string[]): Promise { + let tosFound: ExchangeTosDownloadResult | undefined; + //Remove this when exchange supports multiple content-type in accept header + if (acceptedFormat) + for (const format of acceptedFormat) { + const resp = await downloadExchangeWithTermsOfService( + baseUrl, + ws.http, + timeout, + format, + ); + if (resp.tosContentType === format) { + tosFound = resp; + break; + } + } + if (tosFound !== undefined) return tosFound + // If none of the specified format was found try text/plain + return await downloadExchangeWithTermsOfService( + baseUrl, + ws.http, + timeout, + "text/plain", + ); +} + /** * Update or add exchange DB entry by fetching the /keys and /wire information. * Optionally link the reserve entry to the new or existing @@ -479,7 +530,7 @@ async function updateExchangeFromUrlImpl( logger.info("updating exchange /keys info"); - const timeout = getExchangeRequestTimeout(r); + const timeout = getExchangeRequestTimeout(); const keysInfo = await downloadKeysInfo(baseUrl, ws.http, timeout); @@ -507,33 +558,10 @@ async function updateExchangeFromUrlImpl( logger.info("finished validating exchange /wire info"); - let tosFound: ExchangeTosDownloadResult | undefined; - //Remove this when exchange supports multiple content-type in accept header - if (acceptedFormat) - for (const format of acceptedFormat) { - const resp = await downloadExchangeWithTermsOfService( - baseUrl, - ws.http, - timeout, - format, - ); - if (resp.tosContentType === format) { - tosFound = resp; - break; - } - } - // If none of the specified format was found try text/plain - const tosDownload = - tosFound !== undefined - ? tosFound - : await downloadExchangeWithTermsOfService( - baseUrl, - ws.http, - timeout, - "text/plain", - ); - let recoupGroupId: string | undefined = undefined; + const tosDownload = await downloadTosFromAcceptedFormat(ws, baseUrl, timeout, acceptedFormat) + + let recoupGroupId: string | undefined; logger.trace("updating exchange info in database"); diff --git a/packages/taler-wallet-core/src/wallet.ts b/packages/taler-wallet-core/src/wallet.ts index 182453ff2..b53ba24c4 100644 --- a/packages/taler-wallet-core/src/wallet.ts +++ b/packages/taler-wallet-core/src/wallet.ts @@ -89,9 +89,12 @@ import { } from "./operations/deposits.js"; import { acceptExchangeTermsOfService, + downloadTosFromAcceptedFormat, getExchangeDetails, + getExchangeRequestTimeout, getExchangeTrust, - updateExchangeFromUrl + updateExchangeFromUrl, + updateExchangeTermsOfService } from "./operations/exchanges.js"; import { getMerchantInfo } from "./operations/merchants.js"; import { @@ -441,7 +444,6 @@ async function getExchangeTos( ws, exchangeBaseUrl, acceptedFormat, - true, ); const content = exchangeDetails.termsOfServiceText; const currentEtag = exchangeDetails.termsOfServiceLastEtag; @@ -453,12 +455,34 @@ async function getExchangeTos( ) { throw Error("exchange is in invalid state"); } + if (acceptedFormat && acceptedFormat.findIndex(f => f === contentType) !== -1) { + return { + acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag, + currentEtag, + content, + contentType, + }; + } + + const tosDownload = await downloadTosFromAcceptedFormat(ws, exchangeBaseUrl, getExchangeRequestTimeout(), acceptedFormat); + + if (tosDownload.tosContentType === contentType) { + return { + acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag, + currentEtag, + content, + contentType, + }; + } + await updateExchangeTermsOfService(ws, exchangeBaseUrl, tosDownload) + return { acceptedEtag: exchangeDetails.termsOfServiceAcceptedEtag, - currentEtag, - content, - contentType, + currentEtag: tosDownload.tosEtag, + content: tosDownload.tosText, + contentType: tosDownload.tosContentType, }; + } async function listKnownBankAccounts( @@ -1245,3 +1269,4 @@ class InternalWalletStateImpl implements InternalWalletState { } } } + diff --git a/packages/taler-wallet-webextension/src/NavigationBar.tsx b/packages/taler-wallet-webextension/src/NavigationBar.tsx index e507bf45b..c16bcb53b 100644 --- a/packages/taler-wallet-webextension/src/NavigationBar.tsx +++ b/packages/taler-wallet-webextension/src/NavigationBar.tsx @@ -43,7 +43,7 @@ export enum Pages { backup_provider_detail = "/backup/provider/:pid", backup_provider_add = "/backup/provider/add", - last_activity = "/last-activity", + pending = "/pending", settings = "/settings", settings_exchange_add = "/settings/exchange/add", @@ -84,10 +84,7 @@ export function NavBar({
{i18n.str`Balance`} - {i18n.str`Last Activity`} + {i18n.str`Pending`} {i18n.str`Backup`} {i18n.str`Settings`} {devMode && {i18n.str`Dev`}} diff --git a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx index 206dcb0c5..db26abec6 100644 --- a/packages/taler-wallet-webextension/src/components/TransactionItem.tsx +++ b/packages/taler-wallet-webextension/src/components/TransactionItem.tsx @@ -15,6 +15,8 @@ */ import { + AmountJson, + Amounts, AmountString, Timestamp, Transaction, @@ -37,10 +39,7 @@ import { } from "./styled"; import { Time } from "./Time"; -export function TransactionItem(props: { - tx: Transaction; - multiCurrency: boolean; -}): VNode { +export function TransactionItem(props: { tx: Transaction }): VNode { const tx = props.tx; switch (tx.type) { case TransactionType.Withdrawal: @@ -53,7 +52,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageBank} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); case TransactionType.Payment: @@ -67,7 +65,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageShoppingCart} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); case TransactionType.Refund: @@ -80,7 +77,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageRefund} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); case TransactionType.Tip: @@ -93,7 +89,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageHandHeart} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); case TransactionType.Refresh: @@ -106,7 +101,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageRefresh} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); case TransactionType.Deposit: @@ -119,7 +113,6 @@ export function TransactionItem(props: { timestamp={tx.timestamp} iconPath={imageRefresh} pending={tx.pending} - multiCurrency={props.multiCurrency} /> ); } @@ -144,13 +137,12 @@ function TransactionLayout(props: TransactionLayoutProps): VNode { )} - @@ -166,18 +158,15 @@ interface TransactionLayoutProps { id: string; iconPath: string; pending: boolean; - multiCurrency: boolean; } interface TransactionAmountProps { debitCreditIndicator: "debit" | "credit" | "unknown"; - amount: AmountString | "unknown"; + amount: AmountJson; pending: boolean; - multiCurrency: boolean; } function TransactionAmount(props: TransactionAmountProps): VNode { - const [currency, amount] = props.amount.split(":"); let sign: string; switch (props.debitCreditIndicator) { case "credit": @@ -204,9 +193,8 @@ function TransactionAmount(props: TransactionAmountProps): VNode { > {sign} - {amount} + {Amounts.stringifyValue(props.amount)} - {props.multiCurrency &&
{currency}
} {props.pending &&
PENDING
} ); diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index 2d16b496c..5dd7318b7 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -77,7 +77,7 @@ export const WalletBox = styled.div<{ noPadding?: boolean }>` justify-content: space-between; align-items: center; & > * { - width: 400px; + width: 500px; } & > section { padding: ${({ noPadding }) => (noPadding ? "0px" : "8px")}; @@ -142,7 +142,7 @@ export const Middle = styled.div` export const PopupBox = styled.div<{ noPadding?: boolean; devMode: boolean }>` height: 290px; - width: ${({ devMode }) => (!devMode ? "400px" : "500px")}; + width: 500px; display: flex; flex-direction: column; justify-content: space-between; @@ -783,7 +783,7 @@ export const PopupNavigation = styled.div<{ devMode?: boolean }>` display: flex; & > div { - width: ${({ devMode }) => (!devMode ? "400px" : "500px")}; + width: 500px; } & > div > a { @@ -815,15 +815,16 @@ export const NiceSelect = styled.div` box-shadow: none; background-image: ${image}; - background-position: right 8px center; + background-position: right 4px center; background-repeat: no-repeat; - background-size: 1.5em 1.5em; + background-size: 32px 32px; background-color: white; border-radius: 0.25rem; font-size: 1em; - padding: 0.5em 3em 0.5em 1em; + padding: 8px 32px 8px 8px; + /* 0.5em 3em 0.5em 1em; */ cursor: pointer; } diff --git a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx index f7174c3c5..5169c8540 100644 --- a/packages/taler-wallet-webextension/src/popupEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/popupEntryPoint.tsx @@ -39,7 +39,7 @@ import { SettingsPage } from "./popup/Settings"; import { TalerActionFound } from "./popup/TalerActionFound"; import { ExchangeAddPage } from "./wallet/ExchangeAddPage"; import { IoCProviderForRuntime } from "./context/iocContext"; -import { LastActivityPage } from "./wallet/LastActivityPage"; +import { Pending } from "./wallet/PendingPage"; import { Match } from "preact-router/match"; function main(): void { @@ -125,7 +125,7 @@ function Application(): VNode { }} /> - + 1; - if (balances.length === 0 || !selectedCurrency) { return ( @@ -143,52 +143,73 @@ export function HistoryView({ return (
-

- {currencies.length === 1 ? ( -

{selectedCurrency}
- ) : ( - - { + setCurrencyIndex(Number(e.currentTarget.value)); + }} + > + {currencies.map((currency, index) => { + return ( + + ); + })} + + + )} + {currencyAmount && ( + - {currencies.map((currency, index) => { - return ( - - ); - })} - - - )} - {currencyAmount && ( -

- {Amounts.stringifyValue(currencyAmount)} -

- )} -

-
- goToWalletManualWithdraw(selectedCurrency)} - > - Withdraw - - {currencyAmount && Amounts.isNonZero(currencyAmount) && ( - goToWalletDeposit(selectedCurrency)} + {Amounts.stringifyValue(currencyAmount)} + + )} +
+
+ goToWalletManualWithdraw(selectedCurrency)} > - Deposit - - )} + Withdraw + + {currencyAmount && Amounts.isNonZero(currencyAmount) && ( + goToWalletDeposit(selectedCurrency)} + > + Deposit + + )} +
{datesWithTransaction.length === 0 ? ( @@ -205,11 +226,7 @@ export function HistoryView({ /> {byDate[d].map((tx, i) => ( - + ))} ); diff --git a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx deleted file mode 100644 index e729c2982..000000000 --- a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - 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 - */ - -/** - * - * @author Sebastian Javier Marchano (sebasjm) - */ - -import { createExample } from "../test-utils"; -import { queryToSlashKeys } from "../utils/index"; -import { LastActivityPage as TestedComponent } from "./LastActivityPage"; - -export default { - title: "wallet/last activity", - component: TestedComponent, -}; - -export const InitialState = createExample(TestedComponent, { - onVerify: queryToSlashKeys, -}); diff --git a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx b/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx deleted file mode 100644 index 8ec4c8759..000000000 --- a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx +++ /dev/null @@ -1,35 +0,0 @@ -/* - This file is part of TALER - (C) 2016 GNUnet e.V. - - TALER is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - TALER; see the file COPYING. If not, see -*/ - -import { h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { ButtonPrimary } from "../components/styled"; -import { AddNewActionView } from "./AddNewActionView"; - -export function LastActivityPage(): VNode { - const [addingAction, setAddingAction] = useState(false); - - if (addingAction) { - return setAddingAction(false)} />; - } - - return ( -
-
- setAddingAction(true)}>+ -
- ); -} diff --git a/packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx b/packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx new file mode 100644 index 000000000..cbcb5a824 --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx @@ -0,0 +1,33 @@ +/* + 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 + */ + +/** + * + * @author Sebastian Javier Marchano (sebasjm) + */ + +import { createExample } from "../test-utils"; +import { queryToSlashKeys } from "../utils/index"; +import { Pending as TestedComponent } from "./PendingPage"; + +export default { + title: "wallet/pending", + component: TestedComponent, +}; + +export const InitialState = createExample(TestedComponent, { + onVerify: queryToSlashKeys, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/PendingPage.tsx b/packages/taler-wallet-webextension/src/wallet/PendingPage.tsx new file mode 100644 index 000000000..998095238 --- /dev/null +++ b/packages/taler-wallet-webextension/src/wallet/PendingPage.tsx @@ -0,0 +1,35 @@ +/* + This file is part of TALER + (C) 2016 GNUnet e.V. + + TALER is free software; you can redistribute it and/or modify it under the + terms of the GNU General Public License as published by the Free Software + Foundation; either version 3, or (at your option) any later version. + + TALER is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along with + TALER; see the file COPYING. If not, see +*/ + +import { h, VNode } from "preact"; +import { useState } from "preact/hooks"; +import { ButtonPrimary } from "../components/styled"; +import { AddNewActionView } from "./AddNewActionView"; + +export function Pending(): VNode { + const [addingAction, setAddingAction] = useState(false); + + if (addingAction) { + return setAddingAction(false)} />; + } + + return ( +
+
+ setAddingAction(true)}>+ +
+ ); +} diff --git a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx index dbcf053e2..c8bbc7f7a 100644 --- a/packages/taler-wallet-webextension/src/walletEntryPoint.tsx +++ b/packages/taler-wallet-webextension/src/walletEntryPoint.tsx @@ -38,12 +38,11 @@ import { strings } from "./i18n/strings"; import { NavBar, Pages } from "./NavigationBar"; import { DeveloperPage } from "./popup/DeveloperPage"; import { BackupPage } from "./wallet/BackupPage"; -import { BalancePage } from "./wallet/BalancePage"; import { DepositPage } from "./wallet/DepositPage"; import { ExchangeAddPage } from "./wallet/ExchangeAddPage"; import { HistoryPage } from "./wallet/History"; -import { LastActivityPage } from "./wallet/LastActivityPage"; import { ManualWithdrawPage } from "./wallet/ManualWithdrawPage"; +import { Pending } from "./wallet/PendingPage"; import { ProviderAddPage } from "./wallet/ProviderAddPage"; import { ProviderDetailPage } from "./wallet/ProviderDetailPage"; import { SettingsPage } from "./wallet/Settings"; @@ -124,19 +123,10 @@ function Application(): VNode { - route( - Pages.balance_manual_withdraw.replace(":currency?", ""), - ) - } - goToWalletDeposit={(currency: string) => - route(Pages.balance_deposit.replace(":currency", currency)) - } - goToWalletHistory={(currency: string) => - route(Pages.balance_history.replace(":currency", currency)) - } + component={Redirect} + to={Pages.balance_history.replace(":currency", "")} /> + {/** - * LAST ACTIVITY + * PENDING */} - + {/** @@ -246,7 +233,11 @@ function Application(): VNode { {/** * NOT FOUND */} - + -- cgit v1.2.3