diff options
Diffstat (limited to 'packages/taler-wallet-webextension/src')
13 files changed, 158 insertions, 118 deletions
diff --git a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx index ec5d1e7aa..609c82e10 100644 --- a/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx +++ b/packages/taler-wallet-webextension/src/components/BankDetailsByPaytoType.tsx @@ -21,11 +21,11 @@ import { segwitMinAmount, } from "@gnu-taler/taler-util"; import { Fragment, h, VNode } from "preact"; -import { useEffect, useRef, useState } from "preact/hooks"; +import { useEffect, useMemo, useRef, useState } from "preact/hooks"; import { useTranslationContext } from "../context/translation.js"; import { CopiedIcon, CopyIcon } from "../svg/index.js"; import { Amount } from "./Amount.js"; -import { ButtonBox, TooltipRight } from "./styled/index.js"; +import { ButtonBox, TooltipLeft, TooltipRight } from "./styled/index.js"; export interface BankDetailsProps { payto: PaytoUri | undefined; @@ -62,11 +62,6 @@ export function BankDetailsByPaytoType({ metadata with an minimum amount. </i18n.Translate> </p> - <Row - literal - name={<i18n.Translate>Reserve</i18n.Translate>} - value={subject} - /> <p> <i18n.Translate> @@ -80,6 +75,13 @@ export function BankDetailsByPaytoType({ <td> <Amount value={amount} hideCurrency /> BTC </td> + <td> + <CopyButton + getContent={() => + `${payto.targetPath} ${Amounts.stringifyValue(amount)} BTC` + } + /> + </td> </tr> {payto.segwitAddrs.map((addr, i) => ( <tr key={i}> @@ -87,6 +89,13 @@ export function BankDetailsByPaytoType({ <td> <Amount value={min} hideCurrency /> BTC </td> + <td> + <CopyButton + getContent={() => + `${addr} ${Amounts.stringifyValue(min)} BTC` + } + /> + </td> </tr> ))} </table> @@ -120,6 +129,8 @@ export function BankDetailsByPaytoType({ ) : payto.targetType === "iban" ? ( <Row name={<i18n.Translate>IBAN</i18n.Translate>} value={payto.iban} /> ) : undefined; + + const receiver = payto.params["receiver"] || undefined; return ( <div style={{ @@ -133,11 +144,7 @@ export function BankDetailsByPaytoType({ <table> {accountPart} <Row - name={<i18n.Translate>Exchange</i18n.Translate>} - value={exchangeBaseUrl} - /> - <Row - name={<i18n.Translate>Chosen amount</i18n.Translate>} + name={<i18n.Translate>Amount</i18n.Translate>} value={<Amount value={amount} />} /> <Row @@ -145,11 +152,47 @@ export function BankDetailsByPaytoType({ value={subject} literal /> + {receiver ? ( + <Row + name={<i18n.Translate>Receiver name</i18n.Translate>} + value={receiver} + /> + ) : undefined} </table> </div> ); } +function CopyButton({ getContent }: { getContent: () => string }): VNode { + const [copied, setCopied] = useState(false); + function copyText(): void { + navigator.clipboard.writeText(getContent() || ""); + setCopied(true); + } + useEffect(() => { + if (copied) { + setTimeout(() => { + setCopied(false); + }, 1000); + } + }, [copied]); + + if (!copied) { + return ( + <ButtonBox onClick={copyText}> + <CopyIcon /> + </ButtonBox> + ); + } + return ( + <TooltipLeft content="Copied"> + <ButtonBox disabled> + <CopiedIcon /> + </ButtonBox> + </TooltipLeft> + ); +} + function Row({ name, value, @@ -159,38 +202,15 @@ function Row({ value: string | VNode; literal?: boolean; }): VNode { - const [copied, setCopied] = useState(false); const preRef = useRef<HTMLPreElement>(null); const tdRef = useRef<HTMLTableCellElement>(null); - function copyText(): void { - const content = literal - ? preRef.current?.textContent - : tdRef.current?.textContent; - navigator.clipboard.writeText(content || ""); - setCopied(true); + + function getContent(): string { + return preRef.current?.textContent || tdRef.current?.textContent || ""; } - useEffect(() => { - if (copied) { - setTimeout(() => { - setCopied(false); - }, 1000); - } - }, [copied, preRef]); + return ( <tr> - <td> - {!copied ? ( - <ButtonBox onClick={copyText}> - <CopyIcon /> - </ButtonBox> - ) : ( - <TooltipRight content="Copied"> - <ButtonBox disabled> - <CopiedIcon /> - </ButtonBox> - </TooltipRight> - )} - </td> <td style={{ paddingRight: 8 }}> <b>{name}</b> </td> @@ -206,6 +226,9 @@ function Row({ ) : ( <td ref={tdRef}>{value}</td> )} + <td> + <CopyButton getContent={getContent} /> + </td> </tr> ); } diff --git a/packages/taler-wallet-webextension/src/components/styled/index.tsx b/packages/taler-wallet-webextension/src/components/styled/index.tsx index 605860300..4ed9f8142 100644 --- a/packages/taler-wallet-webextension/src/components/styled/index.tsx +++ b/packages/taler-wallet-webextension/src/components/styled/index.tsx @@ -319,6 +319,19 @@ export const TooltipRight = styled(Tooltip)` } `; +export const TooltipLeft = styled(Tooltip)` + ::before { + top: 0px; + right: 16px; + transform: rotate(90deg); + } + ::after { + top: -50%; + right: 28px; + margin-top: 6px; + } +`; + export const Overlay = styled.div` position: fixed; width: 100%; diff --git a/packages/taler-wallet-webextension/src/mui/Button.tsx b/packages/taler-wallet-webextension/src/mui/Button.tsx index a7657ae29..2f12c1724 100644 --- a/packages/taler-wallet-webextension/src/mui/Button.tsx +++ b/packages/taler-wallet-webextension/src/mui/Button.tsx @@ -51,6 +51,7 @@ interface Props { size?: "small" | "medium" | "large"; startIcon?: VNode | string; variant?: "contained" | "outlined" | "text"; + tooltip?: string; color?: Colors; onClick?: () => Promise<void>; } @@ -213,6 +214,7 @@ export function Button({ startIcon: sip, endIcon: eip, fullWidth, + tooltip, variant = "text", size = "medium", style: parentStyle, @@ -305,6 +307,7 @@ export function Button({ ? theme.palette.grey.A100 : theme.palette[color].dark, }} + title={tooltip} > {startIcon} {children} diff --git a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx index 08479c73c..161296b97 100644 --- a/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx +++ b/packages/taler-wallet-webextension/src/popup/NoBalanceHelp.tsx @@ -21,22 +21,21 @@ import { ButtonHandler } from "../mui/handlers.js"; import { Paper } from "../mui/Paper.js"; import { Typography } from "../mui/Typography.js"; +const margin = css` + margin: 1em; +`; + export function NoBalanceHelp({ goToWalletManualWithdraw, }: { goToWalletManualWithdraw: ButtonHandler; }): VNode { return ( - <Paper - class={css` - margin: 1em; - `} - > - <Alert title="You have no balance." severity="warning"> - <Typography>Withdraw some funds into your wallet.</Typography> + <Paper class={margin}> + <Alert title="Your wallet is empty." severity="info"> <Button fullWidth - color="warning" + color="info" variant="outlined" onClick={goToWalletManualWithdraw.onClick} > diff --git a/packages/taler-wallet-webextension/src/stories.tsx b/packages/taler-wallet-webextension/src/stories.tsx index b4c209a5f..9fe0ca4e4 100644 --- a/packages/taler-wallet-webextension/src/stories.tsx +++ b/packages/taler-wallet-webextension/src/stories.tsx @@ -49,9 +49,6 @@ setupI18n(lang, strings); const Page = styled.div` * { - margin: 0px; - padding: 0px; - font-size: 100%; font-family: Arial, Helvetica, sans-serif; } p:not([class]) { @@ -69,6 +66,12 @@ const SideBar = styled.div` overflow-y: visible; overflow-x: hidden; scroll-behavior: smooth; + + * { + margin: 0px; + padding: 0px; + } + & > { ol { padding: 4px; diff --git a/packages/taler-wallet-webextension/src/svg/download_24px.svg b/packages/taler-wallet-webextension/src/svg/download_24px.svg new file mode 100644 index 000000000..c4ec1c354 --- /dev/null +++ b/packages/taler-wallet-webextension/src/svg/download_24px.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><path d="M5,20h14v-2H5V20z M19,9h-4V3H9v6H5l7,7L19,9z"/></g></svg>
\ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/svg/index.tsx b/packages/taler-wallet-webextension/src/svg/index.tsx index 9ae37963c..7de1c7d4f 100644 --- a/packages/taler-wallet-webextension/src/svg/index.tsx +++ b/packages/taler-wallet-webextension/src/svg/index.tsx @@ -16,16 +16,7 @@ import { h, VNode } from "preact"; export const CopyIcon = (): VNode => ( - <svg - aria-hidden="true" - height="10" - viewBox="0 0 16 16" - version="1.1" - width="10" - data-view-component="true" - class="octicon octicon-copy" - style="display: inline-block;" - > + <svg height="16" viewBox="0 0 16 16" width="16"> <path fill-rule="evenodd" d="M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z" @@ -38,15 +29,7 @@ export const CopyIcon = (): VNode => ( ); export const CopiedIcon = (): VNode => ( - <svg - aria-hidden="true" - height="8" - viewBox="0 0 16 16" - version="1.1" - width="8" - data-view-component="true" - class="octicon octicon-check color-fg-success" - > + <svg height="16" viewBox="0 0 16 16" width="16"> <path fill-rule="evenodd" d="M13.78 4.22a.75.75 0 010 1.06l-7.25 7.25a.75.75 0 01-1.06 0L2.22 9.28a.75.75 0 011.06-1.06L6 10.94l6.72-6.72a.75.75 0 011.06 0z" diff --git a/packages/taler-wallet-webextension/src/svg/upload_24px.svg b/packages/taler-wallet-webextension/src/svg/upload_24px.svg new file mode 100644 index 000000000..c604ef78d --- /dev/null +++ b/packages/taler-wallet-webextension/src/svg/upload_24px.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><g><rect fill="none" height="24" width="24"/></g><g><path d="M5,20h14v-2H5V20z M5,10h4v6h6v-6h4l-7-7L5,10z"/></g></svg>
\ No newline at end of file diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx index ec997dfb3..166b2c007 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx @@ -23,6 +23,7 @@ import { createExample } from "../test-utils.js"; import { DestinationSelectionGetCash, DestinationSelectionSendCash, + SelectCurrencyView, } from "./DestinationSelection.js"; export default { @@ -35,3 +36,9 @@ export const GetCash = createExample(DestinationSelectionGetCash, { export const SendCash = createExample(DestinationSelectionSendCash, { amount: "eur:1", }); +export const SelectCurrency = createExample(SelectCurrencyView, { + list: { + "": "Select a currency", + USD: "USD", + }, +}); diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx index ba5dcf1da..c62504538 100644 --- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx +++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx @@ -186,24 +186,37 @@ export function SelectCurrency({ const list: Record<string, string> = {}; hook.response.exchanges.forEach((e) => (list[e.currency] = e.currency)); list[""] = "Select a currency"; + return <SelectCurrencyView onChange={onChange} list={list} />; +} + +export function SelectCurrencyView({ + onChange, + list, +}: { + onChange: (s: string) => void; + list: Record<string, string>; +}): VNode { + const { i18n } = useTranslationContext(); + return ( <Fragment> - <h1> - <i18n.Translate>Specify the amount and the origin</i18n.Translate> - </h1> + <h2> + <i18n.Translate> + Choose a currency to proceed or add another exchange + </i18n.Translate> + </h2> - <Alert severity="warning"> - Choose a currency to proceed or add more exchanges in the settings tab - </Alert> - <Input> - <SelectList - label={<i18n.Translate>Known currencies</i18n.Translate>} - list={list} - name="lang" - value={""} - onChange={(v) => onChange(v)} - /> - </Input> + <p> + <Input> + <SelectList + label={<i18n.Translate>Known currencies</i18n.Translate>} + list={list} + name="lang" + value={""} + onChange={(v) => onChange(v)} + /> + </Input> + </p> <div style={{ display: "flex", justifyContent: "space-between" }}> <div /> <LinkPrimary href={Pages.settingsExchangeAdd({})}> @@ -320,7 +333,7 @@ export function DestinationSelectionGetCash({ <Grid container spacing={1} columns={1}> {previous2.length > 0 ? ( <Fragment> - <p>Previous origins:</p> + <p>Use previous origins:</p> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <ContactTable> @@ -337,9 +350,9 @@ export function DestinationSelectionGetCash({ </Fragment> ) : undefined} <Grid item> - <p>Create new origin for the money</p> + <p>Or specify a new origin for the money</p> </Grid> - <Grid item container columns={3} spacing={1}> + <Grid item container columns={2} spacing={1}> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <p>From my bank account</p> @@ -355,23 +368,11 @@ export function DestinationSelectionGetCash({ </Grid> <Grid item xs={1}> <Paper style={{ padding: 8 }}> - <p>From someone else</p> - <Button disabled>Request</Button> - </Paper> - </Grid> - <Grid item xs={1}> - <Paper style={{ padding: 8 }}> - <p>From a business or charity</p> + <p>From another wallet</p> <Button disabled>Invoice</Button> </Paper> </Grid> </Grid> - <Grid item columns={1} spacing={1} xs={1}> - <Paper style={{ padding: 8 }}> - <p>From a exchange reserve or purse</p> - <Button disabled>Create</Button> - </Paper> - </Grid> </Grid> </Container> ); @@ -441,7 +442,7 @@ export function DestinationSelectionSendCash({ <Grid container spacing={1} columns={1}> {previous2.length > 0 ? ( <Fragment> - <p>Previous destinations:</p> + <p>Use previous destinations:</p> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <ContactTable> @@ -458,9 +459,9 @@ export function DestinationSelectionSendCash({ </Fragment> ) : undefined} <Grid item> - <p>Create a destination for the money</p> + <p>Or specify a new destination for the money</p> </Grid> - <Grid item container columns={3} spacing={1}> + <Grid item container columns={2} spacing={1}> <Grid item xs={1}> <Paper style={{ padding: 8 }}> <p>To my bank account</p> @@ -469,22 +470,10 @@ export function DestinationSelectionSendCash({ </Grid> <Grid item xs={1}> <Paper style={{ padding: 8 }}> - <p>To someone else</p> + <p>To another wallet</p> <Button disabled>Send</Button> </Paper> </Grid> - <Grid item xs={1}> - <Paper style={{ padding: 8 }}> - <p>To a business or charity</p> - <Button disabled>Pay</Button> - </Paper> - </Grid> - </Grid> - <Grid item columns={1} spacing={1} xs={1}> - <Paper style={{ padding: 8 }}> - <p>To an exchange reserve or purse</p> - <Button disabled>Create</Button> - </Paper> </Grid> </Grid> </Container> diff --git a/packages/taler-wallet-webextension/src/wallet/History.tsx b/packages/taler-wallet-webextension/src/wallet/History.tsx index f02e43391..e885a216d 100644 --- a/packages/taler-wallet-webextension/src/wallet/History.tsx +++ b/packages/taler-wallet-webextension/src/wallet/History.tsx @@ -96,6 +96,8 @@ const term = 1000 * 60 * 60 * 24; function normalizeToDay(x: number): number { return Math.round(x / term) * term; } +import DownloadIcon from "../svg/download_24px.svg"; +import UploadIcon from "../svg/upload_24px.svg"; export function HistoryView({ defaultCurrency, @@ -206,17 +208,19 @@ export function HistoryView({ </div> <div> <Button + tooltip="Transfer money to the wallet" + startIcon={DownloadIcon} variant="contained" - // style={{ marginLeft: 0, marginTop: 8 }} onClick={() => goToWalletManualWithdraw(selectedCurrency)} > <i18n.Translate>Add</i18n.Translate> </Button> {currencyAmount && Amounts.isNonZero(currencyAmount) && ( <Button + tooltip="Transfer money from the wallet" + startIcon={UploadIcon} variant="outlined" color="primary" - // style={{ marginLeft: 0, marginTop: 8 }} onClick={() => goToWalletDeposit(selectedCurrency)} > <i18n.Translate>Send</i18n.Translate> diff --git a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx index 9c9ab7ce4..c574050e0 100644 --- a/packages/taler-wallet-webextension/src/wallet/QrReader.tsx +++ b/packages/taler-wallet-webextension/src/wallet/QrReader.tsx @@ -103,6 +103,7 @@ export function QrReaderPage({ onDetected }: Props): VNode { Read QR from file </InputFile> <div ref={imageRef} /> */} + <h1>Scan a QR code or enter taler:// URI below</h1> <QrVideo ref={videoRef} /> <TextField label="Taler URI" diff --git a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx index 5d21bf306..7d10ad0f4 100644 --- a/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx +++ b/packages/taler-wallet-webextension/src/wallet/ReserveCreated.stories.tsx @@ -55,6 +55,19 @@ export const IBAN = createExample(TestedComponent, { exchangeBaseUrl: "https://exchange.demo.taler.net", }); +export const WithReceiverName = createExample(TestedComponent, { + reservePub: "A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG", + paytoURI: parsePaytoUri( + "payto://iban/ES8877998399652238?amount=COL%3A1&message=Taler+Withdrawal+A05AJGMFNSK4Q62NXR2FKNDB1J4EXTYQTE7VA4M9GZQ4TR06YBNG&receiver=Sebastian", + ), + amount: { + currency: "USD", + value: 10, + fraction: 0, + }, + exchangeBaseUrl: "https://exchange.demo.taler.net", +}); + export const Bitcoin = createExample(TestedComponent, { reservePub: "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00", paytoURI: parsePaytoUri( |