some fixes

This commit is contained in:
Sebastian 2022-08-17 16:12:21 -03:00
parent 17e627c2f0
commit 16777ba205
No known key found for this signature in database
GPG Key ID: BE4FF68352439FC1
13 changed files with 158 additions and 118 deletions

View File

@ -21,11 +21,11 @@ import {
segwitMinAmount, segwitMinAmount,
} from "@gnu-taler/taler-util"; } from "@gnu-taler/taler-util";
import { Fragment, h, VNode } from "preact"; 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 { useTranslationContext } from "../context/translation.js";
import { CopiedIcon, CopyIcon } from "../svg/index.js"; import { CopiedIcon, CopyIcon } from "../svg/index.js";
import { Amount } from "./Amount.js"; import { Amount } from "./Amount.js";
import { ButtonBox, TooltipRight } from "./styled/index.js"; import { ButtonBox, TooltipLeft, TooltipRight } from "./styled/index.js";
export interface BankDetailsProps { export interface BankDetailsProps {
payto: PaytoUri | undefined; payto: PaytoUri | undefined;
@ -62,11 +62,6 @@ export function BankDetailsByPaytoType({
metadata with an minimum amount. metadata with an minimum amount.
</i18n.Translate> </i18n.Translate>
</p> </p>
<Row
literal
name={<i18n.Translate>Reserve</i18n.Translate>}
value={subject}
/>
<p> <p>
<i18n.Translate> <i18n.Translate>
@ -80,6 +75,13 @@ export function BankDetailsByPaytoType({
<td> <td>
<Amount value={amount} hideCurrency /> BTC <Amount value={amount} hideCurrency /> BTC
</td> </td>
<td>
<CopyButton
getContent={() =>
`${payto.targetPath} ${Amounts.stringifyValue(amount)} BTC`
}
/>
</td>
</tr> </tr>
{payto.segwitAddrs.map((addr, i) => ( {payto.segwitAddrs.map((addr, i) => (
<tr key={i}> <tr key={i}>
@ -87,6 +89,13 @@ export function BankDetailsByPaytoType({
<td> <td>
<Amount value={min} hideCurrency /> BTC <Amount value={min} hideCurrency /> BTC
</td> </td>
<td>
<CopyButton
getContent={() =>
`${addr} ${Amounts.stringifyValue(min)} BTC`
}
/>
</td>
</tr> </tr>
))} ))}
</table> </table>
@ -120,6 +129,8 @@ export function BankDetailsByPaytoType({
) : payto.targetType === "iban" ? ( ) : payto.targetType === "iban" ? (
<Row name={<i18n.Translate>IBAN</i18n.Translate>} value={payto.iban} /> <Row name={<i18n.Translate>IBAN</i18n.Translate>} value={payto.iban} />
) : undefined; ) : undefined;
const receiver = payto.params["receiver"] || undefined;
return ( return (
<div <div
style={{ style={{
@ -133,11 +144,7 @@ export function BankDetailsByPaytoType({
<table> <table>
{accountPart} {accountPart}
<Row <Row
name={<i18n.Translate>Exchange</i18n.Translate>} name={<i18n.Translate>Amount</i18n.Translate>}
value={exchangeBaseUrl}
/>
<Row
name={<i18n.Translate>Chosen amount</i18n.Translate>}
value={<Amount value={amount} />} value={<Amount value={amount} />}
/> />
<Row <Row
@ -145,11 +152,47 @@ export function BankDetailsByPaytoType({
value={subject} value={subject}
literal literal
/> />
{receiver ? (
<Row
name={<i18n.Translate>Receiver name</i18n.Translate>}
value={receiver}
/>
) : undefined}
</table> </table>
</div> </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({ function Row({
name, name,
value, value,
@ -159,38 +202,15 @@ function Row({
value: string | VNode; value: string | VNode;
literal?: boolean; literal?: boolean;
}): VNode { }): VNode {
const [copied, setCopied] = useState(false);
const preRef = useRef<HTMLPreElement>(null); const preRef = useRef<HTMLPreElement>(null);
const tdRef = useRef<HTMLTableCellElement>(null); const tdRef = useRef<HTMLTableCellElement>(null);
function copyText(): void {
const content = literal function getContent(): string {
? preRef.current?.textContent return preRef.current?.textContent || tdRef.current?.textContent || "";
: tdRef.current?.textContent;
navigator.clipboard.writeText(content || "");
setCopied(true);
} }
useEffect(() => {
if (copied) {
setTimeout(() => {
setCopied(false);
}, 1000);
}
}, [copied, preRef]);
return ( return (
<tr> <tr>
<td>
{!copied ? (
<ButtonBox onClick={copyText}>
<CopyIcon />
</ButtonBox>
) : (
<TooltipRight content="Copied">
<ButtonBox disabled>
<CopiedIcon />
</ButtonBox>
</TooltipRight>
)}
</td>
<td style={{ paddingRight: 8 }}> <td style={{ paddingRight: 8 }}>
<b>{name}</b> <b>{name}</b>
</td> </td>
@ -206,6 +226,9 @@ function Row({
) : ( ) : (
<td ref={tdRef}>{value}</td> <td ref={tdRef}>{value}</td>
)} )}
<td>
<CopyButton getContent={getContent} />
</td>
</tr> </tr>
); );
} }

View File

@ -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` export const Overlay = styled.div`
position: fixed; position: fixed;
width: 100%; width: 100%;

View File

@ -51,6 +51,7 @@ interface Props {
size?: "small" | "medium" | "large"; size?: "small" | "medium" | "large";
startIcon?: VNode | string; startIcon?: VNode | string;
variant?: "contained" | "outlined" | "text"; variant?: "contained" | "outlined" | "text";
tooltip?: string;
color?: Colors; color?: Colors;
onClick?: () => Promise<void>; onClick?: () => Promise<void>;
} }
@ -213,6 +214,7 @@ export function Button({
startIcon: sip, startIcon: sip,
endIcon: eip, endIcon: eip,
fullWidth, fullWidth,
tooltip,
variant = "text", variant = "text",
size = "medium", size = "medium",
style: parentStyle, style: parentStyle,
@ -305,6 +307,7 @@ export function Button({
? theme.palette.grey.A100 ? theme.palette.grey.A100
: theme.palette[color].dark, : theme.palette[color].dark,
}} }}
title={tooltip}
> >
{startIcon} {startIcon}
{children} {children}

View File

@ -21,22 +21,21 @@ import { ButtonHandler } from "../mui/handlers.js";
import { Paper } from "../mui/Paper.js"; import { Paper } from "../mui/Paper.js";
import { Typography } from "../mui/Typography.js"; import { Typography } from "../mui/Typography.js";
const margin = css`
margin: 1em;
`;
export function NoBalanceHelp({ export function NoBalanceHelp({
goToWalletManualWithdraw, goToWalletManualWithdraw,
}: { }: {
goToWalletManualWithdraw: ButtonHandler; goToWalletManualWithdraw: ButtonHandler;
}): VNode { }): VNode {
return ( return (
<Paper <Paper class={margin}>
class={css` <Alert title="Your wallet is empty." severity="info">
margin: 1em;
`}
>
<Alert title="You have no balance." severity="warning">
<Typography>Withdraw some funds into your wallet.</Typography>
<Button <Button
fullWidth fullWidth
color="warning" color="info"
variant="outlined" variant="outlined"
onClick={goToWalletManualWithdraw.onClick} onClick={goToWalletManualWithdraw.onClick}
> >

View File

@ -49,9 +49,6 @@ setupI18n(lang, strings);
const Page = styled.div` const Page = styled.div`
* { * {
margin: 0px;
padding: 0px;
font-size: 100%;
font-family: Arial, Helvetica, sans-serif; font-family: Arial, Helvetica, sans-serif;
} }
p:not([class]) { p:not([class]) {
@ -69,6 +66,12 @@ const SideBar = styled.div`
overflow-y: visible; overflow-y: visible;
overflow-x: hidden; overflow-x: hidden;
scroll-behavior: smooth; scroll-behavior: smooth;
* {
margin: 0px;
padding: 0px;
}
& > { & > {
ol { ol {
padding: 4px; padding: 4px;

View File

@ -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>

After

Width:  |  Height:  |  Size: 235 B

View File

@ -16,16 +16,7 @@
import { h, VNode } from "preact"; import { h, VNode } from "preact";
export const CopyIcon = (): VNode => ( export const CopyIcon = (): VNode => (
<svg <svg height="16" viewBox="0 0 16 16" width="16">
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;"
>
<path <path
fill-rule="evenodd" 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" 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 => ( export const CopiedIcon = (): VNode => (
<svg <svg height="16" viewBox="0 0 16 16" width="16">
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"
>
<path <path
fill-rule="evenodd" 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" 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"

View File

@ -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>

After

Width:  |  Height:  |  Size: 236 B

View File

@ -23,6 +23,7 @@ import { createExample } from "../test-utils.js";
import { import {
DestinationSelectionGetCash, DestinationSelectionGetCash,
DestinationSelectionSendCash, DestinationSelectionSendCash,
SelectCurrencyView,
} from "./DestinationSelection.js"; } from "./DestinationSelection.js";
export default { export default {
@ -35,3 +36,9 @@ export const GetCash = createExample(DestinationSelectionGetCash, {
export const SendCash = createExample(DestinationSelectionSendCash, { export const SendCash = createExample(DestinationSelectionSendCash, {
amount: "eur:1", amount: "eur:1",
}); });
export const SelectCurrency = createExample(SelectCurrencyView, {
list: {
"": "Select a currency",
USD: "USD",
},
});

View File

@ -186,15 +186,27 @@ export function SelectCurrency({
const list: Record<string, string> = {}; const list: Record<string, string> = {};
hook.response.exchanges.forEach((e) => (list[e.currency] = e.currency)); hook.response.exchanges.forEach((e) => (list[e.currency] = e.currency));
list[""] = "Select a 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 ( return (
<Fragment> <Fragment>
<h1> <h2>
<i18n.Translate>Specify the amount and the origin</i18n.Translate> <i18n.Translate>
</h1> Choose a currency to proceed or add another exchange
</i18n.Translate>
</h2>
<Alert severity="warning"> <p>
Choose a currency to proceed or add more exchanges in the settings tab
</Alert>
<Input> <Input>
<SelectList <SelectList
label={<i18n.Translate>Known currencies</i18n.Translate>} label={<i18n.Translate>Known currencies</i18n.Translate>}
@ -204,6 +216,7 @@ export function SelectCurrency({
onChange={(v) => onChange(v)} onChange={(v) => onChange(v)}
/> />
</Input> </Input>
</p>
<div style={{ display: "flex", justifyContent: "space-between" }}> <div style={{ display: "flex", justifyContent: "space-between" }}>
<div /> <div />
<LinkPrimary href={Pages.settingsExchangeAdd({})}> <LinkPrimary href={Pages.settingsExchangeAdd({})}>
@ -320,7 +333,7 @@ export function DestinationSelectionGetCash({
<Grid container spacing={1} columns={1}> <Grid container spacing={1} columns={1}>
{previous2.length > 0 ? ( {previous2.length > 0 ? (
<Fragment> <Fragment>
<p>Previous origins:</p> <p>Use previous origins:</p>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<ContactTable> <ContactTable>
@ -337,9 +350,9 @@ export function DestinationSelectionGetCash({
</Fragment> </Fragment>
) : undefined} ) : undefined}
<Grid item> <Grid item>
<p>Create new origin for the money</p> <p>Or specify a new origin for the money</p>
</Grid> </Grid>
<Grid item container columns={3} spacing={1}> <Grid item container columns={2} spacing={1}>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<p>From my bank account</p> <p>From my bank account</p>
@ -355,23 +368,11 @@ export function DestinationSelectionGetCash({
</Grid> </Grid>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<p>From someone else</p> <p>From another wallet</p>
<Button disabled>Request</Button>
</Paper>
</Grid>
<Grid item xs={1}>
<Paper style={{ padding: 8 }}>
<p>From a business or charity</p>
<Button disabled>Invoice</Button> <Button disabled>Invoice</Button>
</Paper> </Paper>
</Grid> </Grid>
</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> </Grid>
</Container> </Container>
); );
@ -441,7 +442,7 @@ export function DestinationSelectionSendCash({
<Grid container spacing={1} columns={1}> <Grid container spacing={1} columns={1}>
{previous2.length > 0 ? ( {previous2.length > 0 ? (
<Fragment> <Fragment>
<p>Previous destinations:</p> <p>Use previous destinations:</p>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<ContactTable> <ContactTable>
@ -458,9 +459,9 @@ export function DestinationSelectionSendCash({
</Fragment> </Fragment>
) : undefined} ) : undefined}
<Grid item> <Grid item>
<p>Create a destination for the money</p> <p>Or specify a new destination for the money</p>
</Grid> </Grid>
<Grid item container columns={3} spacing={1}> <Grid item container columns={2} spacing={1}>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<p>To my bank account</p> <p>To my bank account</p>
@ -469,22 +470,10 @@ export function DestinationSelectionSendCash({
</Grid> </Grid>
<Grid item xs={1}> <Grid item xs={1}>
<Paper style={{ padding: 8 }}> <Paper style={{ padding: 8 }}>
<p>To someone else</p> <p>To another wallet</p>
<Button disabled>Send</Button> <Button disabled>Send</Button>
</Paper> </Paper>
</Grid> </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>
</Grid> </Grid>
</Container> </Container>

View File

@ -96,6 +96,8 @@ const term = 1000 * 60 * 60 * 24;
function normalizeToDay(x: number): number { function normalizeToDay(x: number): number {
return Math.round(x / term) * term; return Math.round(x / term) * term;
} }
import DownloadIcon from "../svg/download_24px.svg";
import UploadIcon from "../svg/upload_24px.svg";
export function HistoryView({ export function HistoryView({
defaultCurrency, defaultCurrency,
@ -206,17 +208,19 @@ export function HistoryView({
</div> </div>
<div> <div>
<Button <Button
tooltip="Transfer money to the wallet"
startIcon={DownloadIcon}
variant="contained" variant="contained"
// style={{ marginLeft: 0, marginTop: 8 }}
onClick={() => goToWalletManualWithdraw(selectedCurrency)} onClick={() => goToWalletManualWithdraw(selectedCurrency)}
> >
<i18n.Translate>Add</i18n.Translate> <i18n.Translate>Add</i18n.Translate>
</Button> </Button>
{currencyAmount && Amounts.isNonZero(currencyAmount) && ( {currencyAmount && Amounts.isNonZero(currencyAmount) && (
<Button <Button
tooltip="Transfer money from the wallet"
startIcon={UploadIcon}
variant="outlined" variant="outlined"
color="primary" color="primary"
// style={{ marginLeft: 0, marginTop: 8 }}
onClick={() => goToWalletDeposit(selectedCurrency)} onClick={() => goToWalletDeposit(selectedCurrency)}
> >
<i18n.Translate>Send</i18n.Translate> <i18n.Translate>Send</i18n.Translate>

View File

@ -103,6 +103,7 @@ export function QrReaderPage({ onDetected }: Props): VNode {
Read QR from file Read QR from file
</InputFile> </InputFile>
<div ref={imageRef} /> */} <div ref={imageRef} /> */}
<h1>Scan a QR code or enter taler:// URI below</h1>
<QrVideo ref={videoRef} /> <QrVideo ref={videoRef} />
<TextField <TextField
label="Taler URI" label="Taler URI"

View File

@ -55,6 +55,19 @@ export const IBAN = createExample(TestedComponent, {
exchangeBaseUrl: "https://exchange.demo.taler.net", 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, { export const Bitcoin = createExample(TestedComponent, {
reservePub: "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00", reservePub: "0ZSX8SH0M30KHX8K3Y1DAMVGDQV82XEF9DG1HC4QMQ3QWYT4AF00",
paytoURI: parsePaytoUri( paytoURI: parsePaytoUri(