diff options
author | Sebastian <sebasjm@gmail.com> | 2022-01-24 14:12:12 -0300 |
---|---|---|
committer | Sebastian <sebasjm@gmail.com> | 2022-01-24 14:12:12 -0300 |
commit | 882d6b3710f82d85b2129f09c63f9db45985ef64 (patch) | |
tree | f6304b6bb539e78d3ca4711fa5483dc6657f2163 | |
parent | ec059d42d77a5f092135635f478790e77a2685df (diff) |
last activity -> pending; fix downloadTos
12 files changed, 228 insertions, 135 deletions
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<typeof WalletStoresV1>) => exchangeDetails: x.exchangeDetails, })); +export async function updateExchangeTermsOfService( + ws: InternalWalletState, + exchangeBaseUrl: string, + tos: ExchangeTosDownloadResult, +): Promise<void> { + 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<ExchangeTosDownloadResult> { + 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({ <PopupNavigation devMode={devMode}> <div> <Tab target="/balance" current={path}>{i18n.str`Balance`}</Tab> - <Tab - target="/last-activity" - current={path} - >{i18n.str`Last Activity`}</Tab> + <Tab target="/pending" current={path}>{i18n.str`Pending`}</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>} 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 { </LightText> )} <SmallLightText style={{ marginTop: 5 }}> - <Time timestamp={props.timestamp} format="dd MMM, hh:mm" /> + <Time timestamp={props.timestamp} format="hh:mm" /> </SmallLightText> </Column> <TransactionAmount pending={props.pending} - amount={props.amount} - multiCurrency={props.multiCurrency} + amount={Amounts.parseOrThrow(props.amount)} debitCreditIndicator={props.debitCreditIndicator} /> </HistoryRow> @@ -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 { > <ExtraLargeText> {sign} - {amount} + {Amounts.stringifyValue(props.amount)} </ExtraLargeText> - {props.multiCurrency && <div>{currency}</div>} {props.pending && <div>PENDING</div>} </Column> ); 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 { }} /> - <Route path={Pages.last_activity} component={LastActivityPage} /> + <Route path={Pages.pending} component={Pending} /> <Route path={Pages.balance_transaction} diff --git a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx index 3f550175d..921ac5005 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.stories.tsx @@ -277,3 +277,47 @@ export const FiveOfficialCurrencies = createExample(TestedComponent, { }, ], }); + +export const FiveOfficialCurrenciesWithHighValue = createExample( + TestedComponent, + { + transactions: [exampleData.withdraw], + balances: [ + { + available: "USD:881001321230000", + pendingIncoming: "USD:0", + pendingOutgoing: "USD:0", + hasPendingTransactions: false, + requiresUserInput: false, + }, + { + available: "EUR:10", + pendingIncoming: "TESTKUDOS:0", + pendingOutgoing: "TESTKUDOS:0", + hasPendingTransactions: false, + requiresUserInput: false, + }, + { + available: "COL:443000123123000.5123123", + pendingIncoming: "TESTKUDOS:0", + pendingOutgoing: "TESTKUDOS:0", + hasPendingTransactions: false, + requiresUserInput: false, + }, + { + available: "JPY:1564450000000.6123123", + pendingIncoming: "TESTKUDOS:0", + pendingOutgoing: "TESTKUDOS:0", + hasPendingTransactions: false, + requiresUserInput: false, + }, + { + available: "GBP:736001231231200.23123", + pendingIncoming: "TESTKUDOS:0", + pendingOutgoing: "TESTKUDOS: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 a295ca28f..feeb61c5d 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.tsx @@ -28,6 +28,8 @@ import { ButtonBoxPrimary, ButtonBoxWarning, ButtonPrimary, + CenteredBoldText, + CenteredText, DateSeparator, NiceSelect, WarningBox, @@ -126,8 +128,6 @@ export function HistoryView({ }, {} as { [x: string]: Transaction[] }); const datesWithTransaction = Object.keys(byDate); - const multiCurrency = balances.length > 1; - if (balances.length === 0 || !selectedCurrency) { return ( <WarningBox> @@ -143,52 +143,73 @@ export function HistoryView({ return ( <Fragment> <section> - <p + <div style={{ display: "flex", - justifyContent: "space-between", + flexWrap: "wrap", alignItems: "center", + justifyContent: "space-between", }} > - {currencies.length === 1 ? ( - <div style={{ fontSize: "large" }}>{selectedCurrency}</div> - ) : ( - <NiceSelect> - <select - value={currencyIndex} - onChange={(e) => { - setCurrencyIndex(Number(e.currentTarget.value)); + <div + style={{ + width: "fit-content", + display: "flex", + }} + > + {currencies.length === 1 ? ( + <CenteredText style={{ fontSize: "x-large", margin: 8 }}> + {selectedCurrency} + </CenteredText> + ) : ( + <NiceSelect> + <select + style={{ + fontSize: "x-large", + }} + value={currencyIndex} + onChange={(e) => { + setCurrencyIndex(Number(e.currentTarget.value)); + }} + > + {currencies.map((currency, index) => { + return ( + <option value={index} key={currency}> + {currency} + </option> + ); + })} + </select> + </NiceSelect> + )} + {currencyAmount && ( + <CenteredBoldText + style={{ + display: "inline-block", + fontSize: "x-large", + margin: 8, }} > - {currencies.map((currency, index) => { - return ( - <option value={index} key={currency}> - {currency} - </option> - ); - })} - </select> - </NiceSelect> - )} - {currencyAmount && ( - <h2 style={{ margin: 0 }}> - {Amounts.stringifyValue(currencyAmount)} - </h2> - )} - </p> - <div style={{ marginLeft: "auto", width: "fit-content" }}> - <ButtonPrimary - onClick={() => goToWalletManualWithdraw(selectedCurrency)} - > - Withdraw - </ButtonPrimary> - {currencyAmount && Amounts.isNonZero(currencyAmount) && ( - <ButtonBoxPrimary - onClick={() => goToWalletDeposit(selectedCurrency)} + {Amounts.stringifyValue(currencyAmount)} + </CenteredBoldText> + )} + </div> + <div> + <ButtonPrimary + style={{ marginLeft: 0, marginTop: 8 }} + onClick={() => goToWalletManualWithdraw(selectedCurrency)} > - Deposit - </ButtonBoxPrimary> - )} + Withdraw + </ButtonPrimary> + {currencyAmount && Amounts.isNonZero(currencyAmount) && ( + <ButtonBoxPrimary + style={{ marginLeft: 0, marginTop: 8 }} + onClick={() => goToWalletDeposit(selectedCurrency)} + > + Deposit + </ButtonBoxPrimary> + )} + </div> </div> </section> {datesWithTransaction.length === 0 ? ( @@ -205,11 +226,7 @@ export function HistoryView({ /> </DateSeparator> {byDate[d].map((tx, i) => ( - <TransactionItem - key={i} - tx={tx} - multiCurrency={multiCurrency} - /> + <TransactionItem key={i} tx={tx} /> ))} </Fragment> ); diff --git a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx b/packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx index e729c2982..cbcb5a824 100644 --- a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/PendingPage.stories.tsx @@ -21,10 +21,10 @@ import { createExample } from "../test-utils"; import { queryToSlashKeys } from "../utils/index"; -import { LastActivityPage as TestedComponent } from "./LastActivityPage"; +import { Pending as TestedComponent } from "./PendingPage"; export default { - title: "wallet/last activity", + title: "wallet/pending", component: TestedComponent, }; diff --git a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx b/packages/taler-wallet-webextension/src/wallet/PendingPage.tsx index 8ec4c8759..998095238 100644 --- a/packages/taler-wallet-webextension/src/wallet/LastActivityPage.tsx +++ b/packages/taler-wallet-webextension/src/wallet/PendingPage.tsx @@ -19,7 +19,7 @@ import { useState } from "preact/hooks"; import { ButtonPrimary } from "../components/styled"; import { AddNewActionView } from "./AddNewActionView"; -export function LastActivityPage(): VNode { +export function Pending(): VNode { const [addingAction, setAddingAction] = useState(false); if (addingAction) { 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 path={Pages.balance} - component={BalancePage} - goToWalletManualWithdraw={() => - 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", "")} /> + <Route path={Pages.balance_history} component={HistoryPage} @@ -173,12 +163,9 @@ function Application(): VNode { }} /> {/** - * LAST ACTIVITY + * PENDING */} - <Route - path={Pages.last_activity} - component={LastActivityPage} - /> + <Route path={Pages.pending} component={Pending} /> <Route path={Pages.settings} component={SettingsPage} /> {/** @@ -246,7 +233,11 @@ function Application(): VNode { {/** * NOT FOUND */} - <Route default component={Redirect} to={Pages.balance} /> + <Route + default + component={Redirect} + to={Pages.balance_history.replace(":currency", "")} + /> </Router> </WalletBox> </IoCProviderForRuntime> |