import { AuthenticationProviderStatusOk } from "@gnu-taler/anastasis-core"; import { h, VNode } from "preact"; import { useEffect, 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"; interface Props { providerType?: KnownAuthMethods; onCancel: () => void; } async function testProvider( url: string, expectedMethodType?: string, ): Promise { try { const response = await fetch(new URL("config", url).href); 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", ); } console.log("expected", expectedMethodType); 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, onCancel }: Props): VNode { const reducer = useAnastasisContext(); const [providerURL, setProviderURL] = useState(""); const [error, setError] = useState(); const [testing, setTesting] = useState(false); const providerLabel = providerType ? authMethods[providerType].label : undefined; //FIXME: move this timeout logic into a hook const timeout = useRef(undefined); useEffect(() => { if (timeout) window.clearTimeout(timeout.current); timeout.current = window.setTimeout(async () => { const url = providerURL.endsWith("/") ? providerURL : providerURL + "/"; if (!providerURL || authProviders.includes(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); }, 200); }, [providerURL, reducer]); if (!reducer) { return
no reducer in context
; } if ( !reducer.currentReducerState || !("authentication_providers" in reducer.currentReducerState) ) { return
invalid state
; } async function addProvider(provider_url: string): Promise { await reducer?.transition("add_provider", { provider_url }); onCancel(); } function deleteProvider(provider_url: string): void { reducer?.transition("delete_provider", { provider_url }); } const allAuthProviders = reducer.currentReducerState.authentication_providers || {}; const authProviders = Object.keys(allAuthProviders).filter((provUrl) => { const p = allAuthProviders[provUrl]; if (!providerLabel) { return p && "currency" in p; } else { return ( p && "currency" in p && p.methods.findIndex((m) => m.type === providerType) !== -1 ); } }); let errors = !providerURL ? "Add provider URL" : undefined; let url: string | undefined; try { url = new URL("", providerURL).href; } catch { errors = "Check the URL"; } if (!!error && !errors) { errors = error; } if (!errors && authProviders.includes(url!)) { errors = "That provider is already known"; } return (
{!providerLabel ? (

Add a provider url

) : (

Add a provider url for a {providerLabel} service

)}

Example: https://kudos.demo.anastasis.lu

{testing &&

Testing

}
{authProviders.length > 0 ? ( !providerLabel ? (

Current providers

) : (

Current providers for {providerLabel} service

) ) : !providerLabel ? (

No known providers, add one.

) : (

No known providers for {providerLabel} service

)} {authProviders.map((k) => { const p = allAuthProviders[k] as AuthenticationProviderStatusOk; return ; })}
); } function TableRow({ url, info, onDelete, }: { onDelete: (s: string) => void; 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 (
{url}
Business Name
{info.business_name}
Supported methods
{info.methods.map((m) => m.type).join(",")}
Maximum storage
{info.storage_limit_in_megabytes} Mb
Status
{status}
); }