aboutsummaryrefslogtreecommitdiff
path: root/packages/taler-wallet-webextension/src/wallet
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2022-08-15 21:18:39 -0300
committerSebastian <sebasjm@gmail.com>2022-08-15 21:18:39 -0300
commitcdc8e9afdfb93bd8a90d1e6cf0ea9aa20159e43a (patch)
treee41339241843847f5f4573f08c138149f8dca995 /packages/taler-wallet-webextension/src/wallet
parent004b1544f394ee9dbbd0687d98933932b017f979 (diff)
downloadwallet-core-cdc8e9afdfb93bd8a90d1e6cf0ea9aa20159e43a.tar.xz
destination ui
Diffstat (limited to 'packages/taler-wallet-webextension/src/wallet')
-rw-r--r--packages/taler-wallet-webextension/src/wallet/Application.tsx16
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx4
-rw-r--r--packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx393
-rw-r--r--packages/taler-wallet-webextension/src/wallet/History.tsx2
-rw-r--r--packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx10
5 files changed, 399 insertions, 26 deletions
diff --git a/packages/taler-wallet-webextension/src/wallet/Application.tsx b/packages/taler-wallet-webextension/src/wallet/Application.tsx
index a13094646..6c08ecb71 100644
--- a/packages/taler-wallet-webextension/src/wallet/Application.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/Application.tsx
@@ -57,6 +57,7 @@ import {
DestinationSelectionGetCash,
DestinationSelectionSendCash,
} from "./DestinationSelection.js";
+import { Amounts } from "@gnu-taler/taler-util";
export function Application(): VNode {
const [globalNotification, setGlobalNotification] = useState<
@@ -130,10 +131,14 @@ export function Application(): VNode {
path={Pages.balanceHistory.pattern}
component={HistoryPage}
goToWalletDeposit={(currency: string) =>
- redirectTo(Pages.sendCash({ currency }))
+ redirectTo(Pages.sendCash({ amount: `${currency}:0` }))
}
goToWalletManualWithdraw={(currency?: string) =>
- redirectTo(Pages.receiveCash({ currency }))
+ redirectTo(
+ Pages.receiveCash({
+ amount: !currency ? undefined : `${currency}:0`,
+ }),
+ )
}
/>
<Route
@@ -143,6 +148,9 @@ export function Application(): VNode {
<Route
path={Pages.receiveCash.pattern}
component={DestinationSelectionGetCash}
+ goToWalletManualWithdraw={(amount?: string) =>
+ redirectTo(Pages.balanceManualWithdraw({ amount }))
+ }
/>
<Route
path={Pages.balanceTransaction.pattern}
@@ -226,8 +234,8 @@ export function Application(): VNode {
<Route
path={Pages.ctaPay}
component={PaymentPage}
- goToWalletManualWithdraw={(currency?: string) =>
- redirectTo(Pages.balanceManualWithdraw({ currency }))
+ goToWalletManualWithdraw={(amount?: string) =>
+ redirectTo(Pages.balanceManualWithdraw({ amount }))
}
cancel={() => redirectTo(Pages.balance)}
/>
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx
index 876f683f6..ec997dfb3 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.stories.tsx
@@ -30,8 +30,8 @@ export default {
};
export const GetCash = createExample(DestinationSelectionGetCash, {
- currency: "usd",
+ amount: "usd:0",
});
export const SendCash = createExample(DestinationSelectionSendCash, {
- currency: "eur",
+ amount: "eur:1",
});
diff --git a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
index 187a2412f..5f9c5065c 100644
--- a/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/DestinationSelection.tsx
@@ -14,17 +14,22 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
+import { Amounts } from "@gnu-taler/taler-util";
import { styled } from "@linaria/react";
import { Fragment, h, VNode } from "preact";
+import { useState } from "preact/hooks";
+import {
+ InputWithLabel,
+ LightText,
+ SvgIcon,
+} from "../components/styled/index.js";
+import { useTranslationContext } from "../context/translation.js";
+import { Button } from "../mui/Button.js";
+import { Grid } from "../mui/Grid.js";
import { Paper } from "../mui/Paper.js";
-
-const QrVideo = styled.video`
- width: 80%;
- margin-left: auto;
- margin-right: auto;
- padding: 8px;
- background-color: black;
-`;
+import { TextField } from "../mui/TextField.js";
+import arrowIcon from "../svg/chevron-down.svg";
+import bankIcon from "../svg/ri-bank-line.svg";
const Container = styled.div`
display: flex;
@@ -36,25 +41,379 @@ const Container = styled.div`
interface Props {
action: "send" | "get";
- currency?: string;
+ amount?: string;
+ goToWalletManualWithdraw: (amount: string) => void;
}
-export function DestinationSelectionGetCash({ currency }: Props): VNode {
+type Contact = {
+ icon: string;
+ name: string;
+ description: string;
+};
+
+const ContactTable = styled.table`
+ width: 100%;
+ & > tr > td {
+ padding: 8px;
+ & > div:not([data-disabled]):hover {
+ background-color: lightblue;
+ }
+ color: black;
+ div[data-disabled] > * {
+ color: gray;
+ }
+ }
+
+ & > tr:nth-child(2n) {
+ background: #ebebeb;
+ }
+`;
+
+const MediaExample = styled.div`
+ text-size-adjust: 100%;
+ color: inherit;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ text-transform: none;
+ text-align: left;
+ box-sizing: border-box;
+ align-items: center;
+ display: flex;
+ padding: 8px 8px;
+
+ &[data-disabled]:hover {
+ cursor: inherit;
+ }
+ cursor: pointer;
+`;
+
+const MediaLeft = styled.div`
+ text-size-adjust: 100%;
+
+ color: inherit;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ text-transform: none;
+ text-align: left;
+ box-sizing: border-box;
+ padding-right: 8px;
+ display: block;
+`;
+
+const MediaBody = styled.div`
+ text-size-adjust: 100%;
+
+ font-family: inherit;
+ text-transform: none;
+ text-align: left;
+ box-sizing: border-box;
+ flex: 1 1;
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 1.42857;
+`;
+const MediaRight = styled.div`
+ text-size-adjust: 100%;
+
+ color: inherit;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ text-transform: none;
+ text-align: left;
+ box-sizing: border-box;
+ padding-left: 8px;
+`;
+
+const CircleDiv = styled.div`
+ box-sizing: border-box;
+ align-items: center;
+ background-position: 50%;
+ background-repeat: no-repeat;
+ background-size: cover;
+ border-radius: 50%;
+ display: flex;
+ justify-content: center;
+ margin-left: auto;
+ margin-right: auto;
+ overflow: hidden;
+ text-align: center;
+ text-decoration: none;
+ text-transform: uppercase;
+ transition: background-color 0.15s ease, border-color 0.15s ease,
+ color 0.15s ease;
+ font-size: 16px;
+ background-color: #86a7bd1a;
+ height: 40px;
+ line-height: 40px;
+ width: 40px;
+ border: none;
+`;
+
+function RowExample({
+ info,
+ disabled,
+}: {
+ info: Contact;
+ disabled?: boolean;
+}): VNode {
+ return (
+ <MediaExample data-disabled={disabled}>
+ <MediaLeft>
+ <CircleDiv>
+ <SvgIcon
+ title={info.name}
+ dangerouslySetInnerHTML={{ __html: info.icon }}
+ color="currentColor"
+ />
+ </CircleDiv>
+ </MediaLeft>
+ <MediaBody>
+ <span>{info.name}</span>
+ <LightText>{info.description}</LightText>
+ </MediaBody>
+ <MediaRight>
+ <SvgIcon
+ title="Select this contact"
+ dangerouslySetInnerHTML={{ __html: arrowIcon }}
+ color="currentColor"
+ transform="rotate(-90deg)"
+ />
+ </MediaRight>
+ </MediaExample>
+ );
+}
+
+export function DestinationSelectionGetCash({
+ amount: initialAmount,
+ goToWalletManualWithdraw,
+}: Props): VNode {
+ const parsedInitialAmount = !initialAmount
+ ? undefined
+ : Amounts.parse(initialAmount);
+ const parsedInitialAmountValue = !parsedInitialAmount
+ ? ""
+ : Amounts.stringifyValue(parsedInitialAmount);
+ const currency = parsedInitialAmount?.currency;
+
+ const [amount, setAmount] = useState(parsedInitialAmountValue);
+ const { i18n } = useTranslationContext();
+ const previous1: Contact[] = [];
+ const previous2: Contact[] = [
+ {
+ name: "International Bank",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ {
+ name: "Max",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ {
+ name: "Alex",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ ];
+
+ if (!currency) {
+ return <div>currency not provided</div>;
+ }
+ const currencyAndAmount = `${currency}:${amount}`;
+ const parsedAmount = Amounts.parse(currencyAndAmount);
+ // const dirty = parsedInitialAmountValue !== amount;
+ const invalid = !parsedAmount || Amounts.isZero(parsedAmount);
return (
<Container>
- <p>Request {currency} from:</p>
- <Paper style={{ padding: 8 }}>Bank account</Paper>
- <Paper style={{ padding: 8 }}>Another person</Paper>
+ <h1>
+ <i18n.Translate>Specify the amount and the origin</i18n.Translate>
+ </h1>
+ <TextField
+ label="Amount"
+ type="number"
+ variant="filled"
+ error={invalid}
+ required
+ startAdornment={
+ <div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
+ }
+ value={amount}
+ onChange={(e) => {
+ setAmount(e);
+ }}
+ />
+
+ <Grid container spacing={1} columns={1}>
+ {previous2.length > 0 ? (
+ <Fragment>
+ <p>Previous origins:</p>
+ <Grid item xs={1}>
+ <Paper style={{ padding: 8 }}>
+ <ContactTable>
+ {previous2.map((info, i) => (
+ <tr key={i}>
+ <td>
+ <RowExample info={info} disabled={invalid} />
+ </td>
+ </tr>
+ ))}
+ </ContactTable>
+ </Paper>
+ </Grid>
+ </Fragment>
+ ) : undefined}
+ <Grid item>
+ <p>Create new origin for the money</p>
+ </Grid>
+ <Grid item container columns={3} spacing={1}>
+ <Grid item xs={1}>
+ <Paper style={{ padding: 8 }}>
+ <p>From my bank account</p>
+ <Button
+ disabled={invalid}
+ onClick={async () =>
+ goToWalletManualWithdraw(currencyAndAmount)
+ }
+ >
+ Withdraw
+ </Button>
+ </Paper>
+ </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>
+ <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>
);
}
-export function DestinationSelectionSendCash({ currency }: Props): VNode {
+export function DestinationSelectionSendCash({
+ amount: initialAmount,
+}: Props): VNode {
+ const parsedInitialAmount = !initialAmount
+ ? undefined
+ : Amounts.parse(initialAmount);
+ const parsedInitialAmountValue = !parsedInitialAmount
+ ? ""
+ : Amounts.stringifyValue(parsedInitialAmount);
+ const currency = parsedInitialAmount?.currency;
+
+ const [amount, setAmount] = useState(parsedInitialAmountValue);
+ const { i18n } = useTranslationContext();
+ const previous1: Contact[] = [];
+ const previous2: Contact[] = [
+ {
+ name: "International Bank",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ {
+ name: "Max",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ {
+ name: "Alex",
+ icon: bankIcon,
+ description: "account ending with 3454",
+ },
+ ];
+
+ if (!currency) {
+ return <div>currency not provided</div>;
+ }
+ const currencyAndAmount = `${currency}:${amount}`;
+ const parsedAmount = Amounts.parse(currencyAndAmount);
+ const invalid = !parsedAmount || Amounts.isZero(parsedAmount);
return (
<Container>
- <p>Sending {currency} to:</p>
- <Paper style={{ padding: 8 }}>Bank account</Paper>
- <Paper style={{ padding: 8 }}>Another person</Paper>
+ <h1>
+ <i18n.Translate>Specify the amount and the destination</i18n.Translate>
+ </h1>
+
+ <TextField
+ label="Amount"
+ type="number"
+ variant="filled"
+ required
+ error={invalid}
+ startAdornment={
+ <div style={{ padding: "25px 12px 8px 12px" }}>{currency}</div>
+ }
+ value={amount}
+ onChange={(e) => {
+ setAmount(e);
+ }}
+ />
+
+ <Grid container spacing={1} columns={1}>
+ {previous2.length > 0 ? (
+ <Fragment>
+ <p>Previous destinations:</p>
+ <Grid item xs={1}>
+ <Paper style={{ padding: 8 }}>
+ <ContactTable>
+ {previous2.map((info, i) => (
+ <tr key={i}>
+ <td>
+ <RowExample info={info} disabled={invalid} />
+ </td>
+ </tr>
+ ))}
+ </ContactTable>
+ </Paper>
+ </Grid>
+ </Fragment>
+ ) : undefined}
+ <Grid item>
+ <p>Create a destination for the money</p>
+ </Grid>
+ <Grid item container columns={3} spacing={1}>
+ <Grid item xs={1}>
+ <Paper style={{ padding: 8 }}>
+ <p>To my bank account</p>
+ <Button disabled={invalid}>Deposit</Button>
+ </Paper>
+ </Grid>
+ <Grid item xs={1}>
+ <Paper style={{ padding: 8 }}>
+ <p>To someone else</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 f331cc457..f02e43391 100644
--- a/packages/taler-wallet-webextension/src/wallet/History.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/History.tsx
@@ -210,7 +210,7 @@ export function HistoryView({
// style={{ marginLeft: 0, marginTop: 8 }}
onClick={() => goToWalletManualWithdraw(selectedCurrency)}
>
- <i18n.Translate>Get</i18n.Translate>
+ <i18n.Translate>Add</i18n.Translate>
</Button>
{currencyAmount && Amounts.isNonZero(currencyAmount) && (
<Button
diff --git a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
index a45daa6b1..a292914fb 100644
--- a/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
+++ b/packages/taler-wallet-webextension/src/wallet/ManualWithdrawPage.tsx
@@ -33,11 +33,11 @@ import { CreateManualWithdraw } from "./CreateManualWithdraw.js";
import { ReserveCreated } from "./ReserveCreated.js";
interface Props {
- currency?: string;
+ amount?: string;
onCancel: () => Promise<void>;
}
-export function ManualWithdrawPage({ currency, onCancel }: Props): VNode {
+export function ManualWithdrawPage({ amount, onCancel }: Props): VNode {
const [success, setSuccess] = useState<
| {
response: AcceptManualWithdrawalResult;
@@ -117,12 +117,18 @@ export function ManualWithdrawPage({ currency, onCancel }: Props): VNode {
{} as Record<string, string>,
);
+ const parsedAmount = !amount ? undefined : Amounts.parse(amount);
+ const currency = parsedAmount?.currency;
+ const amountValue = !parsedAmount
+ ? undefined
+ : Amounts.stringifyValue(parsedAmount);
return (
<CreateManualWithdraw
error={error}
exchangeUrlWithCurrency={exchangeList}
onCreate={doCreate}
initialCurrency={currency}
+ initialAmount={amountValue}
/>
);
}