gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-merchant-backoffice] branch master updated: Hello World euFin ban


From: gnunet
Subject: [taler-merchant-backoffice] branch master updated: Hello World euFin bank.
Date: Tue, 07 Dec 2021 14:24:30 +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 bce0789  Hello World euFin bank.
bce0789 is described below

commit bce078986a8c7b1f53c69a78aa9053ac271165be
Author: ms <ms@taler.net>
AuthorDate: Tue Dec 7 14:20:50 2021 +0100

    Hello World euFin bank.
---
 .../components/{FlieButton.tsx => FileButton.tsx}  |   0
 packages/bank/src/components/app.tsx               |   5 +-
 packages/bank/src/components/menu/SideBar.tsx      |   2 +-
 packages/bank/src/index.ts                         |   2 +-
 packages/bank/src/pages/home/index.tsx             | 300 ++++++++++++++++++++-
 5 files changed, 301 insertions(+), 8 deletions(-)

diff --git a/packages/bank/src/components/FlieButton.tsx 
b/packages/bank/src/components/FileButton.tsx
similarity index 100%
rename from packages/bank/src/components/FlieButton.tsx
rename to packages/bank/src/components/FileButton.tsx
diff --git a/packages/bank/src/components/app.tsx 
b/packages/bank/src/components/app.tsx
index f466849..5739f3a 100644
--- a/packages/bank/src/components/app.tsx
+++ b/packages/bank/src/components/app.tsx
@@ -6,10 +6,7 @@ import { Menu } from "./menu";
 const App: FunctionalComponent = () => {
   return (
     <TranslationProvider>
-      <div id="app" class="has-navbar-fixed-top">
-        <Menu title="Bank" />
-        <BankHome />
-      </div>
+      <BankHome />
     </TranslationProvider>
   );
 };
diff --git a/packages/bank/src/components/menu/SideBar.tsx 
b/packages/bank/src/components/menu/SideBar.tsx
index d3a8d0a..d7833df 100644
--- a/packages/bank/src/components/menu/SideBar.tsx
+++ b/packages/bank/src/components/menu/SideBar.tsx
@@ -37,7 +37,7 @@ export function Sidebar({ mobile }: Props): VNode {
       <div class="aside-tools">
         <div class="aside-tools-label">
           <div>
-            <b>GNU Taler Bank</b>
+            <b>euFin bank</b>
           </div>
           <div
             class="is-size-7 has-text-right"
diff --git a/packages/bank/src/index.ts b/packages/bank/src/index.ts
index 4bd7b28..45b2601 100644
--- a/packages/bank/src/index.ts
+++ b/packages/bank/src/index.ts
@@ -1,4 +1,4 @@
 import App from "./components/app";
-import "./scss/main.scss";
+// import "./scss/main.scss";
 
 export default App;
diff --git a/packages/bank/src/pages/home/index.tsx 
b/packages/bank/src/pages/home/index.tsx
index 4833c3e..3cf78b3 100644
--- a/packages/bank/src/pages/home/index.tsx
+++ b/packages/bank/src/pages/home/index.tsx
@@ -1,5 +1,301 @@
-import { h } from "preact";
+import { h, Fragment } from "preact";
+import {useState} from "preact/hooks";
+import axios from "axios";
 
+
+/**********************************************
+ * Type definitions for states and API calls. *
+ *********************************************/
+
+/**
+ * Has the information to reach and
+ * authenticate at the bank's backend.
+ */
+interface BackendStateType {
+  url: string;
+  username: string | undefined;
+  password: string | undefined;
+}
+
+/**
+ * Request body of /register.
+ */
+interface RegistrationRequestType {
+  username: string;
+  password: string;
+}
+
+/**
+ * Track page state.
+ */
+interface PageStateType {
+  isLoggedIn: boolean;
+  hasProblem: boolean;
+}
+
+/**
+ * Bank account specific information.
+ */
+interface AccountStateType {
+  balance: string | undefined;
+  /* FIXME: Need history here.  */
+
+  /**
+   * Error message to diplay when one of the
+   * account state entries failed to arrive.
+   */
+  error: string | undefined;
+}
+
+/*******************
+ * State managers. *
+ ******************/
+
+/**
+ * Return getters and setters for
+ * 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)
+] {
+  return useState<BackendStateType>(state);
+}
+
+function useAccountState<AccountStateType>(
+  state: AccountStateType = {
+    balance: undefined,
+    error: undefined
+}): [
+  AccountStateType, (fn: (state: AccountStateType) => void) => void
+] {
+  return useState<AccountStateType>(state);
+}
+
+function usePageState(
+  state: PageStateType = {
+    isLoggedIn: false,
+    hasProblem: false,
+}): [
+  PageStateType, (newState: PageStateType) => any |
+    ((fn: (state: PageStateType) => void) => void)
+] {
+  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);});}
+  );
+}
+
+/******************
+ * HTTP wrappers. *
+ *****************/
+
+/**
+ * Wrappers for HTTP requests specific to individual API calls.
+ * Each wrapper will (1) manage HTTP requests and responses,
+ * and (2) update the state accordingly.
+ *
+ * Their signature is:
+ * RequestType x ResponseType x use*State() => void
+ *
+ * For example, a 'wrap()' function can look like:
+ *
+ *  wrap(url: string,
+ *       req: WrapTypeReq,
+ *       state: StateType // Will only have setters used.
+ *  ) {
+ *
+ *    let cb: (resp: WrapTypeRes) => void = {
+ *      // implementation here.
+ *      // ..
+ *      state.setter(...)
+ *    };
+ *
+ *    post(url, req, (resp) => cb(resp))
+ *  }
+ *
+ ***/
+
+
+/**
+ * This function requests GET /accounts/{account_name}.
+ *
+ * It's only a information retriever, without any effect
+ * on the state.
+ */
+async function accountInfoCall(
+  backendState: BackendStateType,
+  accountStateSetter: (fn: (state: AccountStateType) => void) => void
+) {
+  const url = new URL(`accounts/${backendState.username}`, backendState.url);
+  const handleResp = (respStatus: number) => {
+    switch (respStatus) {
+      case 200: {
+        accountStateSetter(state => ({...state, balance: "1 EUR"}));
+       break;
+      }
+      default: {
+        accountStateSetter(state => ({...state, error: "Missing 
information."}));
+      }
+    }
+  };
+  const resp = await get(url)
+  handleResp(resp)
+}
+
+/**
+ * This function requests /register.
+ *
+ * This function is responsible to change two states:
+ * the backend's (to store the login credentials) and
+ * the page's (to indicate a successful login or a problem).
+ */
+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,
+) {
+  console.log("Try to register", req);
+  var handleResp = (respStatus: number) => {
+    switch (respStatus) {
+      case 200: {
+        pageStateSetter(state => ({...state, isLoggedIn: true}));
+        backendStateSetter(state => ({
+         ...state,
+         username: req.username,
+         password: req.password,
+       }));
+        break;
+      }
+      default: {
+        pageStateSetter(state => ({...state, hasProblem: true}));
+      }
+    }
+  }
+  var resp = await post(url, req);
+  handleResp(resp);
+}
+
+/**************************
+ * Functional components. *
+ *************************/
+
+/**
+ * Show only the account's balance.
+ */
+export function Account(props: {balance: string}) {
+  return <p>Your balance is {props.balance}</p>;
+}
+
+/**
+ * If the user is logged in, it displays
+ * the balance, otherwise it offers to login.
+ */
 export function BankHome() {
-  return <section class="section">hello bank</section>;
+  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};
+  }
+
+  if (pageState.hasProblem) {
+    return <p>Page has a problem.</p>;
+  }
+
+  if (pageState.isLoggedIn) {
+    if (typeof accountState.error !== "undefined") {
+      console.log(accountState);
+      return <p>The page could not load correctly: {accountState.error}</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>;
+
+    /**
+     * FIXME: need to offer a Taler withdraw button here.
+     */
+
+    /**
+     * FIXME: need to offer the withdraw confirmation page,
+     * after the wallet has 'selected' an exchange and a reserve.
+     *
+     * The selection can be detected by asking the withdrawal
+     * status to the bank's backend.
+     */
+  }
+  
+  // Proceede collecting registration data.
+  return <div>
+    <input type="text"
+           placeholder="username"
+           onInput={(e): void => {
+            registrationData = {...registrationData, username: 
e.currentTarget.value};
+          }}
+    / >
+    <input type="text"
+           placeholder="password"
+           onInput={(e): void => {
+            registrationData = {...registrationData, password: 
e.currentTarget.value};
+          }}
+    / >
+
+    <button
+      onClick={() => {registrationCall(
+        backendState.url,
+        prepareRegistrationRequest(),
+        backendStateSetter,
+        pageStateSetter,
+      )}}>Submit</button>
+  </div>
 }

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]