[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[taler-merchant-backoffice] branch master updated: bank: import and conf
From: |
gnunet |
Subject: |
[taler-merchant-backoffice] branch master updated: bank: import and configure SWR |
Date: |
Mon, 13 Dec 2021 14:33:56 +0100 |
This is an automated email from the git hooks/post-receive script.
ms pushed a commit to branch master
in repository merchant-backoffice.
The following commit(s) were added to refs/heads/master by this push:
new 0dc4e08 bank: import and configure SWR
0dc4e08 is described below
commit 0dc4e08923a9c4ee743898b6590a28c8151b160e
Author: ms <ms@taler.net>
AuthorDate: Mon Dec 13 14:33:08 2021 +0100
bank: import and configure SWR
---
packages/bank/package.json | 5 +-
packages/bank/src/pages/home/index.tsx | 188 +++++++++++++++------------------
2 files changed, 90 insertions(+), 103 deletions(-)
diff --git a/packages/bank/package.json b/packages/bank/package.json
index cf46a3d..12852c1 100644
--- a/packages/bank/package.json
+++ b/packages/bank/package.json
@@ -32,7 +32,8 @@
"preact": "^10.5.15",
"preact-render-to-string": "^5.1.19",
"preact-router": "^3.2.1",
- "qrcode-generator": "^1.4.4"
+ "qrcode-generator": "^1.4.4",
+ "swr": "1.1"
},
"devDependencies": {
"@creativebulma/bulma-tooltip": "^1.2.0",
@@ -42,6 +43,8 @@
"@storybook/addon-links": "6.2.9",
"@storybook/preact": "6.2.9",
"@storybook/preset-scss": "^1.0.3",
+ "@testing-library/preact": "^2.0.1",
+ "@testing-library/preact-hooks": "^1.1.0",
"@types/enzyme": "^3.10.10",
"@types/jest": "^27.0.2",
"@typescript-eslint/eslint-plugin": "^5.3.0",
diff --git a/packages/bank/src/pages/home/index.tsx
b/packages/bank/src/pages/home/index.tsx
index 3cf78b3..1d1ae26 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -1,6 +1,8 @@
-import { h, Fragment } from "preact";
-import {useState} from "preact/hooks";
+import useSWR, { SWRConfig } from "swr";
+import { h, Fragment, ComponentChildren, VNode } from "preact";
+import { useState, useEffect, StateUpdater } from "preact/hooks";
import axios from "axios";
+import { Buffer } from 'buffer';
/**********************************************
@@ -13,8 +15,8 @@ import axios from "axios";
*/
interface BackendStateType {
url: string;
- username: string | undefined;
- password: string | undefined;
+ username: string;
+ password: string;
}
/**
@@ -31,20 +33,23 @@ interface RegistrationRequestType {
interface PageStateType {
isLoggedIn: boolean;
hasProblem: boolean;
+ error?: string;
}
/**
* Bank account specific information.
*/
interface AccountStateType {
- balance: string | undefined;
+ balance: string;
/* FIXME: Need history here. */
+}
- /**
- * Error message to diplay when one of the
- * account state entries failed to arrive.
- */
- error: string | undefined;
+/*******************
+ * Helpers. *
+ ******************/
+
+const getRootPath = () => {
+ return typeof window !== undefined ? window.location.origin +
window.location.pathname : '/';
}
/*******************
@@ -56,59 +61,40 @@ interface AccountStateType {
* login credentials and backend's
* base URL.
*/
-function useBackendState(
- state: BackendStateType = {
- url: window.location.href, // Should never change.
- username: undefined,
- password: undefined,
-}): [
- BackendStateType,
- (newState: BackendStateType) => void |
- ((fn: (oldState: BackendStateType) => void) => void)
+type BackendStateTypeOpt = BackendStateType | undefined;
+function useBackendState(state?: BackendStateType): [
+ BackendStateTypeOpt, StateUpdater<BackendStateTypeOpt>
] {
- return useState<BackendStateType>(state);
+ if (state) return useState<BackendStateTypeOpt>(state);
+ return useState<BackendStateTypeOpt>();
}
-function useAccountState<AccountStateType>(
- state: AccountStateType = {
- balance: undefined,
- error: undefined
-}): [
- AccountStateType, (fn: (state: AccountStateType) => void) => void
-] {
- return useState<AccountStateType>(state);
+/**
+ * Keep mere business information, like account balance or
+ * transactions history.
+ */
+type AccountStateTypeOpt = AccountStateType | undefined;
+function useAccountState(state?: AccountStateType): [
+ AccountStateTypeOpt, StateUpdater<AccountStateTypeOpt>] {
+ if (state) return useState<AccountStateTypeOpt>(state);
+ return useState<AccountStateTypeOpt>();
}
function usePageState(
state: PageStateType = {
isLoggedIn: false,
hasProblem: false,
-}): [
- PageStateType, (newState: PageStateType) => any |
- ((fn: (state: PageStateType) => void) => void)
-] {
+}): [PageStateType, StateUpdater<PageStateType>] {
return useState<PageStateType>(state);
}
-/************
- * Helpers. *
- ***********/
-
-async function post(url: string, data: any): Promise<number> {
- // Mock 200 OK responses, at this moment.
- return new Promise(
- // (res, rej) => {setTimeout(() => {res(404);});}
- (res, rej) => {setTimeout(() => {res(200);});}
- );
-}
-
-async function get(url: string): Promise<number> {
- // Mock 200 OK responses, at this moment.
- return new Promise(
- (res, rej) => {setTimeout(() => {res(404);});}
- // (res, rej) => {setTimeout(() => {res(200);});}
- );
-}
+/**
+ * Request preparators.
+ *
+ * These functions aim at sanitizing the input received
+ * from users - for example via a HTML form - and create
+ * a HTTP request object out of that.
+ */
/******************
* HTTP wrappers. *
@@ -163,8 +149,7 @@ async function accountInfoCall(
}
}
};
- const resp = await get(url)
- handleResp(resp)
+ handleResp(200)
}
/**
@@ -177,10 +162,9 @@ async function accountInfoCall(
async function registrationCall(
url: string,
req: RegistrationRequestType,
- // On success, that will update the username and password to the state.
- backendStateSetter: (fn: (state: BackendStateType) => void) => void,
- // Communicate the request outcome to the page.
- pageStateSetter: (fn: (state: PageStateType) => void) => void,
+ backendStateSetter: StateUpdater<BackendStateTypeOpt>,
+ pageStateSetter: StateUpdater<PageStateType>,
+ // pageStateSetter: (fn: (state: PageStateType) => void) => void,
) {
console.log("Try to register", req);
var handleResp = (respStatus: number) => {
@@ -189,6 +173,7 @@ async function registrationCall(
pageStateSetter(state => ({...state, isLoggedIn: true}));
backendStateSetter(state => ({
...state,
+ url: url,
username: req.username,
password: req.password,
}));
@@ -199,8 +184,7 @@ async function registrationCall(
}
}
}
- var resp = await post(url, req);
- handleResp(resp);
+ handleResp(200);
}
/**************************
@@ -214,53 +198,50 @@ export function Account(props: {balance: string}) {
return <p>Your balance is {props.balance}</p>;
}
+/**
+ * Factor out login credentials.
+ */
+function SWRWithCredentials(props: any): VNode {
+ const { username, password } = props;
+ const headers = new Headers();
+ headers.append(
+ "Authorization",
+ `Basic ${Buffer.from(username + ":" + password).toString("base64")}`
+ );
+ return (
+ <SWRConfig value={{fetcher: (url) => fetch(url, {headers: headers}).then(r
=> (r.json()))}}>
+ {props.children}
+ </SWRConfig>);
+}
+
/**
* If the user is logged in, it displays
* the balance, otherwise it offers to login.
*/
-export function BankHome() {
- var [backendState, backendStateSetter] = useBackendState<BackendStateType>();
- var [pageState, pageStateSetter] = usePageState<PageStateType>();
- var [accountState, accountStateSetter] = useAccountState<AccountStateType>();
-
- // Prepare/check registration request.
- var registrationData: {}; // Untyped collector of user input.
- let prepareRegistrationRequest = (): RegistrationRequestType => {
-
- console.log("Preparing registration request", registrationData);
- if (!("username" in registrationData)) {
- pageStateSetter({...pageState, hasProblem: true});
- return;
- }
- if (!("password" in registrationData)) {
- pageStateSetter({...pageState, hasProblem: true});
- return;
- }
- const u: string = registrationData["username"]
- const p: string = registrationData["password"]
- // Here, input is valid.
- return {username: u, password: p};
- }
+export function BankHome(): VNode {
+ var [backendState, backendStateSetter] = useBackendState();
+ var [pageState, pageStateSetter] = usePageState();
+ var [accountState, accountStateSetter] = useAccountState();
if (pageState.hasProblem) {
return <p>Page has a problem.</p>;
}
+ /**
+ * Credentials were correct, now try to render the
+ * bank account page, with balance and transactions
+ * history */
if (pageState.isLoggedIn) {
- if (typeof accountState.error !== "undefined") {
- console.log(accountState);
- return <p>The page could not load correctly: {accountState.error}</p>;
+ if (typeof backendState === "undefined") {
+ console.log("Credentials not found in state, even after login.");
+ pageStateSetter((state) => ({...state, hasProblem: true}));
+ return <p>Page has a problem</p>;
}
- if (typeof accountState.balance === "undefined") {
- // Need one: request and trigger new state!
- accountInfoCall(backendState, accountStateSetter);
- return;
- }
-
- return <Fragment>
- <p>Welcome {backendState.username}!</p>
- <Account balance={accountState.balance} />
- </Fragment>;
+ return <SWRWithCredentials
+ username={backendState.username}
+ password={backendState.password}>
+ <p>Hey!</p>
+ </SWRWithCredentials>
/**
* FIXME: need to offer a Taler withdraw button here.
@@ -275,27 +256,30 @@ export function BankHome() {
*/
}
- // Proceede collecting registration data.
+ var registrationData: RegistrationRequestType;
return <div>
<input type="text"
placeholder="username"
+ required
onInput={(e): void => {
registrationData = {...registrationData, username:
e.currentTarget.value};
}}
/ >
<input type="text"
placeholder="password"
+ required
onInput={(e): void => {
registrationData = {...registrationData, password:
e.currentTarget.value};
}}
/ >
<button
- onClick={() => {registrationCall(
- backendState.url,
- prepareRegistrationRequest(),
- backendStateSetter,
- pageStateSetter,
- )}}>Submit</button>
+ onClick={() => {
+ registrationCall(
+ getRootPath(),
+ registrationData,
+ backendStateSetter,
+ pageStateSetter,
+ )}}>Submit</button>
</div>
}
--
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [taler-merchant-backoffice] branch master updated: bank: import and configure SWR,
gnunet <=