aboutsummaryrefslogtreecommitdiff
path: root/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
diff options
context:
space:
mode:
authorSebastian <sebasjm@gmail.com>2021-11-01 16:10:49 -0300
committerSebastian <sebasjm@gmail.com>2021-11-01 16:10:55 -0300
commit88d142d2098ad87613222e9a0c6df478a78f6528 (patch)
treec5552e43a4641edb233fc858670d50c41d2c7c9b /packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
parentea2acd1d3caa21f23127687214045a49d8fea0ad (diff)
downloadwallet-core-88d142d2098ad87613222e9a0c6df478a78f6528.tar.xz
more styling
added placeholders for inputs import declaration for png next button now has tooltip providing info about whats missing a lot more of examples for UI testing added qr dependency for totp rendering added email and field input types added all auth method setup screens added modal when there is not auth provider merge continent and country into location section others improvements as well...
Diffstat (limited to 'packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx')
-rw-r--r--packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx199
1 files changed, 138 insertions, 61 deletions
diff --git a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index e9ffccbac..f4d2aee58 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -1,19 +1,19 @@
/* eslint-disable @typescript-eslint/camelcase */
-import { AuthMethod, ReducerStateBackup } from "anastasis-core";
-import { h, VNode } from "preact";
+import { AuthMethod } from "anastasis-core";
+import { ComponentChildren, h, VNode } from "preact";
import { useState } from "preact/hooks";
import { useAnastasisContext } from "../../context/anastasis";
-import { AnastasisReducerApi } from "../../hooks/use-anastasis-reducer";
-import { AuthMethodEmailSetup } from "./AuthMethodEmailSetup";
-import { AuthMethodPostSetup } from "./AuthMethodPostSetup";
-import { AuthMethodQuestionSetup } from "./AuthMethodQuestionSetup";
-import { AuthMethodSmsSetup } from "./AuthMethodSmsSetup";
+import { authMethods, KnownAuthMethods } from "./authMethodSetup";
import { AnastasisClientFrame } from "./index";
+
+
+const getKeys = Object.keys as <T extends object>(obj: T) => Array<keyof T>
+
export function AuthenticationEditorScreen(): VNode {
- const [selectedMethod, setSelectedMethod] = useState<string | undefined>(
- undefined
- );
+ const [noProvidersAck, setNoProvidersAck] = useState(false)
+ const [selectedMethod, setSelectedMethod] = useState<KnownAuthMethods | undefined>(undefined);
+
const reducer = useAnastasisContext()
if (!reducer) {
return <div>no reducer in context</div>
@@ -21,7 +21,29 @@ export function AuthenticationEditorScreen(): VNode {
if (!reducer.currentReducerState || reducer.currentReducerState.backup_state === undefined) {
return <div>invalid state</div>
}
+ const configuredAuthMethods: AuthMethod[] = reducer.currentReducerState.authentication_methods ?? [];
+ const haveMethodsConfigured = configuredAuthMethods.length > 0;
+
+ function removeByIndex(index: number): void {
+ if (reducer) reducer.transition("delete_authentication", {
+ authentication_method: index,
+ })
+ }
+
+ const camByType: { [s: string]: AuthMethodWithRemove[] } = {}
+ for (let index = 0; index < configuredAuthMethods.length; index++) {
+ const cam = {
+ ...configuredAuthMethods[index],
+ remove: () => removeByIndex(index)
+ }
+ const prevValue = camByType[cam.type] || []
+ prevValue.push(cam)
+ camByType[cam.type] = prevValue;
+ }
+
+
const providers = reducer.currentReducerState.authentication_providers!;
+
const authAvailableSet = new Set<string>();
for (const provKey of Object.keys(providers)) {
const p = providers[provKey];
@@ -31,79 +53,106 @@ export function AuthenticationEditorScreen(): VNode {
}
}
}
+
if (selectedMethod) {
const cancel = (): void => setSelectedMethod(undefined);
const addMethod = (args: any): void => {
reducer.transition("add_authentication", args);
setSelectedMethod(undefined);
};
- const methodMap: Record<
- string, (props: AuthMethodSetupProps) => h.JSX.Element
- > = {
- sms: AuthMethodSmsSetup,
- question: AuthMethodQuestionSetup,
- email: AuthMethodEmailSetup,
- post: AuthMethodPostSetup,
- };
- const AuthSetup = methodMap[selectedMethod] ?? AuthMethodNotImplemented;
+
+ const AuthSetup = authMethods[selectedMethod].screen ?? AuthMethodNotImplemented;
return (
<AuthSetup
cancel={cancel}
+ configured={camByType[selectedMethod] || []}
addAuthMethod={addMethod}
method={selectedMethod} />
);
}
- function MethodButton(props: { method: string; label: string }): VNode {
+ function MethodButton(props: { method: KnownAuthMethods }): VNode {
return (
- <button
- disabled={!authAvailableSet.has(props.method)}
- onClick={() => {
- setSelectedMethod(props.method);
- if (reducer) reducer.dismissError();
- }}
- >
- {props.label}
- </button>
+ <div class="block">
+ <button
+ style={{ justifyContent: 'space-between' }}
+ class="button is-fullwidth"
+ onClick={() => {
+ if (!authAvailableSet.has(props.method)) {
+ //open add sms dialog
+ } else {
+ setSelectedMethod(props.method);
+ }
+ if (reducer) reducer.dismissError();
+ }}
+ >
+ <div style={{ display: 'flex' }}>
+ <span class="icon ">
+ {authMethods[props.method].icon}
+ </span>
+ <span>
+ {authMethods[props.method].label}
+ </span>
+ </div>
+ {!authAvailableSet.has(props.method) &&
+ <span class="icon has-text-danger" >
+ <i class="mdi mdi-exclamation-thick" />
+ </span>
+ }
+ {camByType[props.method] &&
+ <span class="tag is-info" >
+ {camByType[props.method].length}
+ </span>
+ }
+ </button>
+ </div>
);
}
- const configuredAuthMethods: AuthMethod[] = reducer.currentReducerState.authentication_methods ?? [];
- const haveMethodsConfigured = configuredAuthMethods.length;
+ const errors = !haveMethodsConfigured ? "There is not enough authentication methods." : undefined;
return (
- <AnastasisClientFrame title="Backup: Configure Authentication Methods">
- <div>
- <MethodButton method="sms" label="SMS" />
- <MethodButton method="email" label="Email" />
- <MethodButton method="question" label="Question" />
- <MethodButton method="post" label="Physical Mail" />
- <MethodButton method="totp" label="TOTP" />
- <MethodButton method="iban" label="IBAN" />
- </div>
- <h2>Configured authentication methods</h2>
- {haveMethodsConfigured ? (
- configuredAuthMethods.map((x, i) => {
- return (
- <p key={i}>
- {x.type} ({x.instructions}){" "}
- <button
- onClick={() => reducer.transition("delete_authentication", {
- authentication_method: i,
- })}
- >
- Delete
- </button>
+ <AnastasisClientFrame title="Backup: Configure Authentication Methods" hideNext={errors}>
+ <div class="columns">
+ <div class="column is-half">
+ <div>
+ {getKeys(authMethods).map(method => <MethodButton key={method} method={method} />)}
+ </div>
+ {authAvailableSet.size === 0 && <ConfirmModal active={!noProvidersAck} onCancel={() => setNoProvidersAck(true)} description="No providers founds" label="Add a provider manually">
+ We have found no trusted cloud providers for your recovery secret. You can add a provider manually.
+ To add a provider you must know the provider URL (e.g. https://provider.com)
+ <p>
+ <a>More about cloud providers</a>
</p>
- );
- })
- ) : (
- <p>No authentication methods configured yet.</p>
- )}
+ </ConfirmModal>}
+
+ {/* {haveMethodsConfigured && (
+ configuredAuthMethods.map((x, i) => {
+ return (
+ <p key={i}>
+ {x.type} ({x.instructions}){" "}
+ <button class="button is-danger is-small"
+ onClick={() => reducer.transition("delete_authentication", {
+ authentication_method: i,
+ })}
+ >
+ Remove
+ </button>
+ </p>
+ );
+ })
+ )} */}
+ </div>
+ <div class="column is-half">
+ When recovering your wallet, you will be asked to verify your identity via the methods you configure here.
+ </div>
+ </div>
</AnastasisClientFrame>
);
}
+type AuthMethodWithRemove = AuthMethod & { remove: () => void }
export interface AuthMethodSetupProps {
method: string;
addAuthMethod: (x: any) => void;
+ configured: AuthMethodWithRemove[];
cancel: () => void;
}
@@ -116,8 +165,36 @@ function AuthMethodNotImplemented(props: AuthMethodSetupProps): VNode {
);
}
-interface AuthenticationEditorProps {
- reducer: AnastasisReducerApi;
- backupState: ReducerStateBackup;
+
+function ConfirmModal({ active, description, onCancel, onConfirm, children, danger, disabled, label = 'Confirm' }: Props): VNode {
+ return <div class={active ? "modal is-active" : "modal"}>
+ <div class="modal-background " onClick={onCancel} />
+ <div class="modal-card" style={{ maxWidth: 700 }}>
+ <header class="modal-card-head">
+ {!description ? null : <p class="modal-card-title"><b>{description}</b></p>}
+ <button class="delete " aria-label="close" onClick={onCancel} />
+ </header>
+ <section class="modal-card-body">
+ {children}
+ </section>
+ <footer class="modal-card-foot">
+ <button class="button" onClick={onCancel} >Dismiss</button>
+ <div class="buttons is-right" style={{ width: '100%' }}>
+ <button class={danger ? "button is-danger " : "button is-info "} disabled={disabled} onClick={onConfirm} >{label}</button>
+ </div>
+ </footer>
+ </div>
+ <button class="modal-close is-large " aria-label="close" onClick={onCancel} />
+ </div>
}
+interface Props {
+ active?: boolean;
+ description?: string;
+ onCancel?: () => void;
+ onConfirm?: () => void;
+ label?: string;
+ children?: ComponentChildren;
+ danger?: boolean;
+ disabled?: boolean;
+}