[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant-backoffice] 01/02: copying pybank's look. WIP
From: |
gnunet |
Subject: |
[taler-merchant-backoffice] 01/02: copying pybank's look. WIP |
Date: |
Thu, 07 Apr 2022 07:34:17 +0200 |
This is an automated email from the git hooks/post-receive script.
ms pushed a commit to branch master
in repository merchant-backoffice.
commit af7f0fa9df6165e3d82246d4077ac2d4da6cb597
Author: ms <ms@taler.net>
AuthorDate: Tue Apr 5 10:47:50 2022 +0200
copying pybank's look. WIP
---
packages/bank/src/components/QR.tsx | 2 +-
packages/bank/src/pages/home/index.tsx | 172 +++++++++++++++++++++++++--------
2 files changed, 134 insertions(+), 40 deletions(-)
diff --git a/packages/bank/src/components/QR.tsx
b/packages/bank/src/components/QR.tsx
index 9a05f60..f154dde 100644
--- a/packages/bank/src/components/QR.tsx
+++ b/packages/bank/src/components/QR.tsx
@@ -36,7 +36,7 @@ export function QR({ text }: { text: string }): VNode {
width: "100%",
display: "flex",
flexDirection: "column",
- alignItems: "center",
+ alignItems: "left",
}}
>
<div
diff --git a/packages/bank/src/pages/home/index.tsx
b/packages/bank/src/pages/home/index.tsx
index 03f0661..0c08c87 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -109,6 +109,9 @@ interface AccountStateType {
* Helpers. *
***********/
+function genCaptchaNumbers(): string {
+ return `${Math.floor(Math.random() * 10)} + ${Math.floor(Math.random() *
10)}`;
+}
/**
* Bring the state to show the public accounts page.
*/
@@ -124,7 +127,7 @@ function goPublicAccounts(pageStateSetter:
StateUpdater<PageStateType>) {
function validateAmount(maybeAmount: string): any {
const amountRegex = "^[0-9]+(\.[0-9]+)?$";
if (typeof maybeAmount !== "undefined" || maybeAmount !== "") {
- console.log("Maybe valid amount", maybeAmount);
+ console.log("Maybe valid amount: " + maybeAmount);
// tolerating comma instead of point.
maybeAmount = maybeAmount.replace(",", ".");
const re = RegExp(amountRegex)
@@ -515,9 +518,8 @@ async function createTransactionCall(
* user should receive a QR code of the "taler://withdraw/" type and
* supposed to scan it with their phone.
*
- * TODO: (1) after the scan, the page should refresh itself and inform the
- * user about the operation's outcome. (2) use POST helper.
- */
+ * TODO: (1) after the scan, the page should refresh itself and inform
+ * the user about the operation's outcome. (2) use POST helper. */
async function createWithdrawalCall(
amount: string,
backendState: BackendStateTypeOpt,
@@ -563,7 +565,7 @@ async function createWithdrawalCall(
console.log("Withdrawal operation created!");
let resp = await res.json();
- pageStateSetter((prevState) => ({
+ pageStateSetter((prevState: PageStateType) => ({
...prevState,
withdrawalInProgress: true,
talerWithdrawUri: resp.taler_withdraw_uri,
@@ -710,7 +712,7 @@ function BankFrame(Props: any): VNode {
</div>
<a href="https://taler.net/">
<img
- src={talerLogo}
+ src={talerLogo}
height="100"
width="224"
style="margin: 2em 2em">
@@ -815,7 +817,7 @@ function PaytoWireTransfer(Props: any): VNode {
href="#"
onClick={() => {
console.log("switch to raw payto form");
- pageStateSetter((prevState) => ({...prevState, isRawPayto: true}));
+ pageStateSetter((prevState: any) => ({...prevState, isRawPayto:
true}));
}}>{i18n`Want to try the raw payto://-format?`}
</a></p>
</div>
@@ -861,13 +863,107 @@ function PaytoWireTransfer(Props: any): VNode {
}
/**
- * Let user choose a amount and submit the withdtawal.
+ * Offer the QR code (and a clickable taler://-link) to
+ * permit the passing of exchange and reserve details to
+ * the bank. Poll the backend until such operation is done.
+ */
+function TalerWithdrawalQRCode(Props: any): VNode {
+ const [pageState, pageStateSetter] = useContext(PageContext);
+ const {
+ withdrawalId,
+ talerWithdrawUri,
+ accountLabel,
+ backendState } = Props;
+ const i18n = useTranslator();
+ console.log(`Showing withdraw URI: ${talerWithdrawUri}`);
+ // polling the wallet:
+ const { data, error } = useSWR(
+
`integration-api/accounts/${accountLabel}/withdrawal-operation/${withdrawalId}`
+ );
+ const captchaNumbers = {
+ a: Math.floor(Math.random() * 10),
+ b: Math.floor(Math.random() * 10)
+ }
+ var captchaAnswer = "";
+ // fall here as long as the wallet did NOT communicate:
+ if (typeof error !== "undefined") {
+ console.log("transactions not found error", error);
+ switch(error.status) {
+ case 404: {
+ return (<section id="main" class="content">
+ <h1 class="nav">{i18n`Withdraw to a Taler Wallet`}</h1>
+ <p>{i18n`You can use this QR code to withdraw to your mobile
wallet:`}</p>
+ {QR({text: talerWithdrawUri})}
+ <p>Click <a href={talerWithdrawUri}>{i18n`this link`}</a> to open
your Taler wallet!</p>
+ <br /><br />
+ <button onClick={() => {
+ pageStateSetter((prevState: PageStateType) => {
+ const { withdrawalOutcome, withdrawalId, talerWithdrawUri,
...rest } = prevState;
+ return { ...rest, withdrawalInProgress: false };
+ })}}>{i18n`Close`}</button>
+ </section>);
+ }
+ default: {
+ pageStateSetter((prevState: PageStateType) => ({...prevState,
hasError: true, error: error }))
+ return <p>Could not complete the withdrawal: {error}</p>
+ }
+ }
+ }
+ // here the reserve public key and exchange payment details are known to the
bank,
+ // ask for a confirmation (used to be the CAPTCHA page):
+ return (<Fragment>
+ <h1 class="nav">{i18n`Confirm Withdrawal`}</h1>
+ <p><Translate>
+ Please, authorize this operation by answering the following question.
+ </Translate></p>
+ <div>
+ <label>What is <em>{captchaNumbers.a} + {captchaNumbers.b}</em>
? </label>
+ <input
+ type="text"
+ required
+ onInput={(e): void => {
+ captchaAnswer = e.currentTarget.value;
+ }} />
+ <input
+ type="submit"
+ value="confirm"
+ onClick={ () => {
+ if (captchaAnswer == (captchaNumbers.a +
captchaNumbers.b).toString()) {
+ confirmWithdrawalCall(
+ backendState,
+ pageState.withdrawalId,
+ pageStateSetter)
+ return;
+ }
+ pageStateSetter((prevState: PageStateType) =>
+ ({...prevState, hasError: true, error: "Answer is wrong."}))
+ }} />
+ <input
+ type="submit"
+ value="abort"
+ onClick={ () =>
+ abortWithdrawalCall(
+ backendState,
+ pageState.withdrawalId,
+ pageStateSetter
+ )} />
+ </div>
+ <p><Translate>
+ A this point, a <b>real</b> bank would ask for an additional
+ authentication proof (PIN/TAN, one time password, ..), instead
+ of a simple calculation.
+ </Translate></p>
+ </Fragment>);
+}
+
+/**
+ * Let the user choose an amount and submit the withdtawal.
*/
function TalerWithdrawal(Props: any): VNode {
const {backendState, pageStateSetter} = Props;
const currency = useContext(CurrencyContext);
const i18n = useTranslator();
- var submitAmount = ""; // without currency.
+ var submitAmount = "5.00"; // must match the first <select> child.
const amountRegex = "^[0-9]+(\.[0-9]+)?$";
var submitButton = <input
@@ -893,10 +989,14 @@ function TalerWithdrawal(Props: any): VNode {
<div>
<h2>{i18n`Withdraw Money into a Taler wallet`}</h2>
<div id="reserve-form"
- class="pure-form"
- name="tform">
+ class="pure-form"
+ name="tform">
{i18n`Amount to withdraw`}:
- <select id="reserve-amount" name="withdraw-amount" class="amount"
autofocus>
+ <select id="reserve-amount"
+ name="withdraw-amount"
+ class="amount" autofocus
+ onChange={(e): void => {
+ submitAmount = e.currentTarget.value; }}>
<option value="5.00">5.00</option>
<option value="10.00">10.00</option>
<option value="15.00">15.00</option>
@@ -1092,6 +1192,7 @@ function Account(Props: any): VNode {
tryManualTransfer,
withdrawalOutcome,
transferOutcome,
+ withdrawalId,
talerWithdrawUri } = pageState;
const i18n = useTranslator();
const logOut = (
@@ -1201,14 +1302,17 @@ function Account(Props: any): VNode {
* the outcome.
*/
if (talerWithdrawUri) {
- console.log(`Showing withdraw URI: ${talerWithdrawUri}`);
- return (<Fragment>
- <p>Scan the following QR code, and then confirm!</p>
- <div>{QR({text: talerWithdrawUri})}</div>
- <a href={talerWithdrawUri}></a>
- <p>Withdraw address: <pre>{talerWithdrawUri}</pre></p>
- {Props.children}
- </Fragment>);
+ console.log("Bank created a new Taler withdrawal");
+ return (
+ <BankFrame>
+ {logOut}<br />
+ <TalerWithdrawalQRCode
+ accountLabel={accountLabel}
+ backendState={backendState}
+ withdrawalId={withdrawalId}
+ talerWithdrawUri={talerWithdrawUri} />
+ </BankFrame>
+ );
}
const balance = parseAmount(data.balance.amount)
if (tryManualTransfer) {
@@ -1231,13 +1335,10 @@ function Account(Props: any): VNode {
</section>
<CurrencyContext.Provider value={balance.currency}>
{Props.children}
+ <TalerWithdrawal
+ backendState={backendState}
+ pageStateSetter={pageStateSetter} />
</CurrencyContext.Provider>
- {
- withdrawalInProgress && !transferOutcome &&
- <TalerWithdrawal
- backendState={backendState}
- pageStateSetter={pageStateSetter} />
- }
<section id="main">
<article>
<h2>{i18n`Latest transactions:`}</h2>
@@ -1416,19 +1517,10 @@ export function BankHome(): VNode {
backendUrl={backendState.url}>
<PageContext.Provider value={[pageState, pageStateSetter]}>
<Account accountLabel={backendState.username}
backendState={backendState}>
-
- { /**
- * No action is currently being performed (page is 'pristine'):
- * offer the Taler withdrawal button.
- */
- !pageState.withdrawalInProgress && !pageState.transferOutcome &&
<TalerWithdrawal
- backendState={backendState}
- pageStateSetter={pageStateSetter} />
- }
-
{ /**
* Wire transfer reached a persisten state: offer to
- * return back to the pristine profile page.
+ * return back to the pristine profile page. FIXME:
+ * move this into the Account component.
*/
pageState.transferOutcome && <button onClick={() => {
pageStateSetter((prevState) => {
@@ -1438,7 +1530,8 @@ export function BankHome(): VNode {
{ /**
* Withdrawal reached a persisten state: offer to
- * return back to the pristine profile page.
+ * return back to the pristine profile page. FIXME:
+ * move this into the Account component.
*/
pageState.withdrawalOutcome && <button onClick={() => {
pageStateSetter((prevState) => {
@@ -1452,7 +1545,8 @@ export function BankHome(): VNode {
{ /**
* The withdrawal QR code is rendered: offer to confirm
- * or abort the operation.
+ * or abort the operation. FIXME: move this into the Account
+ * component.
*/
pageState.talerWithdrawUri && <div><button onClick={() => {
confirmWithdrawalCall(
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.