From cdc8e9afdfb93bd8a90d1e6cf0ea9aa20159e43a Mon Sep 17 00:00:00 2001 From: Sebastian Date: Mon, 15 Aug 2022 21:18:39 -0300 Subject: destination ui --- .../src/wallet/Application.tsx | 16 +- .../src/wallet/DestinationSelection.stories.tsx | 4 +- .../src/wallet/DestinationSelection.tsx | 393 ++++++++++++++++++++- .../src/wallet/History.tsx | 2 +- .../src/wallet/ManualWithdrawPage.tsx | 10 +- 5 files changed, 399 insertions(+), 26 deletions(-) (limited to 'packages/taler-wallet-webextension/src/wallet') 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`, + }), + ) } /> + redirectTo(Pages.balanceManualWithdraw({ amount })) + } /> - 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 */ +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 ( + + + + + + + + {info.name} + {info.description} + + + + + + ); +} + +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
currency not provided
; + } + const currencyAndAmount = `${currency}:${amount}`; + const parsedAmount = Amounts.parse(currencyAndAmount); + // const dirty = parsedInitialAmountValue !== amount; + const invalid = !parsedAmount || Amounts.isZero(parsedAmount); return ( -

Request {currency} from:

- Bank account - Another person +

+ Specify the amount and the origin +

+ {currency} + } + value={amount} + onChange={(e) => { + setAmount(e); + }} + /> + + + {previous2.length > 0 ? ( + +

Previous origins:

+ + + + {previous2.map((info, i) => ( + + + + + + ))} + + + +
+ ) : undefined} + +

Create new origin for the money

+
+ + + +

From my bank account

+ +
+
+ + +

From someone else

+ +
+
+ + +

From a business or charity

+ +
+
+
+ + +

From a exchange reserve or purse

+ +
+
+
); } -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
currency not provided
; + } + const currencyAndAmount = `${currency}:${amount}`; + const parsedAmount = Amounts.parse(currencyAndAmount); + const invalid = !parsedAmount || Amounts.isZero(parsedAmount); return ( -

Sending {currency} to:

- Bank account - Another person +

+ Specify the amount and the destination +

+ + {currency} + } + value={amount} + onChange={(e) => { + setAmount(e); + }} + /> + + + {previous2.length > 0 ? ( + +

Previous destinations:

+ + + + {previous2.map((info, i) => ( + + + + + + ))} + + + +
+ ) : undefined} + +

Create a destination for the money

+
+ + + +

To my bank account

+ +
+
+ + +

To someone else

+ +
+
+ + +

To a business or charity

+ +
+
+
+ + +

To an exchange reserve or purse

+ +
+
+
); } 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)} > - Get + Add {currencyAmount && Amounts.isNonZero(currencyAmount) && (