import { AuthenticationProviderStatusOk } from "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}
}