From c898eae296b21e7ca3be7b2fd524d639f492b337 Mon Sep 17 00:00:00 2001
From: Sebastian <sebasjm@gmail.com>
Date: Mon, 8 Nov 2021 15:33:41 -0300
Subject: manage provider screen

---
 .../src/pages/home/AddingProviderScreen.tsx        | 164 +++++++++++++++------
 1 file changed, 121 insertions(+), 43 deletions(-)

(limited to 'packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx')

diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
index 9c83da49e..d2d22374e 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
@@ -1,11 +1,8 @@
-/* eslint-disable @typescript-eslint/camelcase */
-import {
-  encodeCrock,
-  stringToBytes
-} from "@gnu-taler/taler-util";
+import { AuthenticationProviderStatusOk } from "anastasis-core";
 import { h, VNode } from "preact";
-import { useLayoutEffect, useRef, useState } from "preact/hooks";
+import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
 import { TextInput } from "../../components/fields/TextInput";
+import { useAnastasisContext } from "../../context/anastasis";
 import { authMethods, KnownAuthMethods } from "./authMethod";
 import { AnastasisClientFrame } from "./index";
 
@@ -13,38 +10,70 @@ interface Props {
   providerType?: KnownAuthMethods;
   cancel: () => void;
 }
+
+
+async function testProvider(url: string, expectedMethodType?: string): Promise<void> {
+  try {
+    const response = await fetch(`${url}/config`)
+    const json = await (response.json().catch(d => ({})))
+    if (!("methods" in json) || !Array.isArray(json.methods)) {
+      throw Error("This provider doesn't have authentication method. Check the provider URL")
+    }
+    if (!expectedMethodType) {
+      return
+    }
+    let found = false
+    for (let i = 0; i < json.methods.length && !found; i++) {
+      found = json.methods[i].type !== expectedMethodType
+    }
+    if (!found) {
+      throw Error(`This provider does not support authentication method ${expectedMethodType}`)
+    }
+    return
+  } catch (e) {
+    console.log("error", e)
+    const error = e instanceof Error ?
+      Error(`There was an error testing this provider, try another one. ${e.message}`) :
+      Error(`There was an error testing this provider, try another one.`)
+    throw error
+  }
+
+}
+
 export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
+  const reducer = useAnastasisContext();
+
   const [providerURL, setProviderURL] = useState("");
   const [error, setError] = useState<string | undefined>()
+  const [testing, setTesting] = useState(false)
   const providerLabel = providerType ? authMethods[providerType].label : undefined
 
-  function testProvider(): void {
-    setError(undefined)
+  //FIXME: move this timeout logic into a hook
+  const timeout = useRef<number | undefined>(undefined);
+  useEffect(() => {
+    if (timeout) window.clearTimeout(timeout.current)
+    timeout.current = window.setTimeout(async () => {
+      const url = providerURL.endsWith('/') ? providerURL.substring(0, providerURL.length - 1) : providerURL
+      if (!url) return;
+      try {
+        setTesting(true)
+        await testProvider(url, providerType)
+        // this is use as tested but everything when ok
+        // undefined will mean that the field is not dirty
+        setError("")
+      } catch (e) {
+        console.log("tuvieja", e)
+        if (e instanceof Error) setError(e.message)
+      }
+      setTesting(false)
+    }, 1000);
+  }, [providerURL])
 
-    fetch(`${providerURL}/config`)
-      .then(r => r.json().catch(d => ({})))
-      .then(r => {
-        if (!("methods" in r) || !Array.isArray(r.methods)) {
-          setError("This provider doesn't have authentication method. Check the provider URL")
-          return;
-        }
-        if (!providerLabel) {
-          setError("")
-          return
-        }
-        let found = false
-        for (let i = 0; i < r.methods.length && !found; i++) {
-          found = r.methods[i].type !== providerType
-        }
-        if (!found) {
-          setError(`This provider does not support authentication method ${providerLabel}`)
-        }
-      })
-      .catch(e => {
-        setError(`There was an error testing this provider, try another one. ${e.message}`)
-      })
 
+  if (!reducer) {
+    return <div>no reducer in context</div>;
   }
+
   function addProvider(): void {
     // addAuthMethod({
     //   authentication_method: {
@@ -54,10 +83,6 @@ export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
     //   },
     // });
   }
-  const inputRef = useRef<HTMLInputElement>(null);
-  useLayoutEffect(() => {
-    inputRef.current?.focus();
-  }, []);
 
   let errors = !providerURL ? 'Add provider URL' : undefined
   try {
@@ -69,14 +94,25 @@ export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
     errors = error
   }
 
+  if (!reducer.currentReducerState || !("authentication_providers" in reducer.currentReducerState)) {
+    return <div>invalid state</div>
+  }
+
+  const authProviders = reducer.currentReducerState.authentication_providers || {}
+
   return (
     <AnastasisClientFrame hideNav
-      title={!providerLabel ? `Backup: Adding a provider` : `Backup: Adding a ${providerLabel} provider`}
+      title="Backup: Manage providers"
       hideNext={errors}>
       <div>
-        <p>
-          Add a provider url {errors}
-        </p>
+        {!providerLabel ?
+          <p>
+            Add a provider url
+          </p> :
+          <p>
+            Add a provider url for a {providerLabel} service
+          </p>
+        }
         <div class="container">
           <TextInput
             label="Provider URL"
@@ -84,18 +120,60 @@ export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
             grabFocus
             bind={[providerURL, setProviderURL]} />
         </div>
+        <p class="block">
+          Example: https://kudos.demo.anastasis.lu
+        </p>
+
+        {testing && <p class="block has-text-info">Testing</p>}
         {!!error && <p class="block has-text-danger">{error}</p>}
         {error === "" && <p class="block has-text-success">This provider worked!</p>}
-        <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
-          <button class="button" onClick={testProvider}>TEST</button>
-        </div>
-        <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
+
+        <div class="block" style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}>
           <button class="button" onClick={cancel}>Cancel</button>
           <span data-tooltip={errors}>
-            <button class="button is-info" disabled={errors !== undefined} onClick={addProvider}>Add</button>
+            <button class="button is-info" disabled={error !== "" || testing} onClick={addProvider}>Add</button>
           </span>
         </div>
+
+        <p class="subtitle">
+          Current providers
+        </p>
+        {/* <table class="table"> */}
+        {Object.keys(authProviders).map(k => {
+          const p = authProviders[k]
+          if (("currency" in p)) {
+            return <TableRow url={k} info={p} />
+          }
+        }
+        )}
+        {/* </table> */}
       </div>
     </AnastasisClientFrame>
   );
 }
+function TableRow({ url, info }: { url: string, info: AuthenticationProviderStatusOk }) {
+  const [status, setStatus] = useState("checking")
+  useEffect(function () {
+    testProvider(url.endsWith('/') ? url.substring(0, url.length - 1) : url)
+      .then(function () { setStatus('responding') })
+      .catch(function () { setStatus('failed to contact') })
+  })
+  return <div class="box" style={{ display: 'flex', justifyContent: 'space-between' }}>
+    <div>
+      <div class="subtitle">{url}</div>
+      <dl>
+        <dt><b>Business Name</b></dt>
+        <dd>{info.business_name}</dd>
+        <dt><b>Supported methods</b></dt>
+        <dd>{info.methods.map(m => m.type).join(',')}</dd>
+        <dt><b>Maximum storage</b></dt>
+        <dd>{info.storage_limit_in_megabytes} Mb</dd>
+        <dt><b>Status</b></dt>
+        <dd>{status}</dd>
+      </dl>
+    </div>
+    <div class="block" style={{ marginTop: 'auto', marginBottom: 'auto', display: 'flex', justifyContent: 'space-between', flexDirection: 'column' }}>
+      <button class="button is-danger" >Remove</button>
+    </div>
+  </div>
+}
\ No newline at end of file
-- 
cgit v1.2.3

