diff options
Diffstat (limited to 'packages/anastasis-webui/src/pages/home')
15 files changed, 188 insertions, 64 deletions
diff --git a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx index 4a937d855..1b50779e0 100644 --- a/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/AttributeEntryScreen.tsx @@ -44,6 +44,11 @@ export function AttributeEntryScreen(): VNode { setValue={(v: string) => setAttrs({ ...attrs, [spec.name]: v })} spec={spec} errorMessage={error} + onConfirm={() => { + if (!hasErrors) { + setAskUserIfSure(true) + } + }} value={value} /> ); @@ -104,6 +109,7 @@ interface AttributeEntryFieldProps { setValue: (newValue: string) => void; spec: UserAttributeSpec; errorMessage: string | undefined; + onConfirm: () => void; } const possibleBirthdayYear: Array<number> = []; for (let i = 0; i < 100; i++) { @@ -117,6 +123,7 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode { grabFocus={props.isFirst} label={props.spec.label} years={possibleBirthdayYear} + onConfirm={props.onConfirm} error={props.errorMessage} bind={[props.value, props.setValue]} /> @@ -125,6 +132,7 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode { <PhoneNumberInput grabFocus={props.isFirst} label={props.spec.label} + onConfirm={props.onConfirm} error={props.errorMessage} bind={[props.value, props.setValue]} /> @@ -133,6 +141,7 @@ function AttributeEntryField(props: AttributeEntryFieldProps): VNode { <TextInput grabFocus={props.isFirst} label={props.spec.label} + onConfirm={props.onConfirm} error={props.errorMessage} bind={[props.value, props.setValue]} /> diff --git a/packages/anastasis-webui/src/pages/home/ConfirmModal.tsx b/packages/anastasis-webui/src/pages/home/ConfirmModal.tsx index e3561d892..c9c59c1b4 100644 --- a/packages/anastasis-webui/src/pages/home/ConfirmModal.tsx +++ b/packages/anastasis-webui/src/pages/home/ConfirmModal.tsx @@ -1,4 +1,6 @@ +import { differenceInBusinessDays } from "date-fns"; import { ComponentChildren, h, VNode } from "preact"; +import { useLayoutEffect, useRef } from "preact/hooks"; import { AsyncButton } from "../../components/AsyncButton"; export interface ConfirmModelProps { @@ -17,7 +19,7 @@ export function ConfirmModal({ active, description, onCancel, onConfirm, children, danger, disabled, label = "Confirm", cancelLabel = "Dismiss" }: ConfirmModelProps): VNode { return ( - <div class={active ? "modal is-active" : "modal"}> + <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"> @@ -33,8 +35,11 @@ export function ConfirmModal({ <button class="button" onClick={onCancel}> {cancelLabel} </button> - <div class="buttons is-right" style={{ width: "100%" }}> + <div class="buttons is-right" style={{ width: "100%" }} onKeyDown={(e) => { + if (e.key === 'Escape' && onCancel) onCancel() + }}> <AsyncButton + grabFocus class={danger ? "button is-danger " : "button is-info "} disabled={disabled} onClick={onConfirm} diff --git a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx index 226e43ddf..be8135ef5 100644 --- a/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/SecretEditorScreen.tsx @@ -10,10 +10,12 @@ import { FileInput, FileTypeContent } from "../../components/fields/FileInput"; export function SecretEditorScreen(): VNode { const reducer = useAnastasisContext(); const [secretValue, setSecretValue] = useState(""); - const [secretFile, _setSecretFile] = useState<FileTypeContent | undefined>(undefined); + const [secretFile, _setSecretFile] = useState<FileTypeContent | undefined>( + undefined, + ); function setSecretFile(v) { - setSecretValue("") // reset secret value when uploading a file - _setSecretFile(v) + setSecretValue(""); // reset secret value when uploading a file + _setSecretFile(v); } const currentSecretName = @@ -34,14 +36,16 @@ export function SecretEditorScreen(): VNode { } const secretNext = async (): Promise<void> => { - const secret = secretFile ? { - value: encodeCrock(stringToBytes(secretValue)), - filename: secretFile.name, - mime: secretFile.type, - } : { - value: encodeCrock(stringToBytes(secretValue)), - mime: "text/plain", - } + const secret = secretFile + ? { + value: encodeCrock(stringToBytes(secretValue)), + filename: secretFile.name, + mime: secretFile.type, + } + : { + value: encodeCrock(stringToBytes(secretValue)), + mime: "text/plain", + }; return reducer.runTransaction(async (tx) => { await tx.transition("enter_secret_name", { name: secretName, @@ -55,9 +59,14 @@ export function SecretEditorScreen(): VNode { await tx.transition("next", {}); }); }; - const errors = !secretName ? 'Add a secret name' : ( - (!secretValue && !secretFile) ? 'Add a secret value or a choose a file to upload' : undefined - ) + const errors = !secretName + ? "Add a secret name" + : !secretValue && !secretFile + ? "Add a secret value or a choose a file to upload" + : undefined; + function goNextIfNoErrors(): void { + if (!errors) secretNext(); + } return ( <AnastasisClientFrame hideNext={errors} @@ -69,12 +78,14 @@ export function SecretEditorScreen(): VNode { label="Secret name:" tooltip="The secret name allows you to identify your secret when restoring it. It is a label that you can choose freely." grabFocus + onConfirm={goNextIfNoErrors} bind={[secretName, setSecretName]} /> </div> <div class="block"> <TextInput disabled={!!secretFile} + onConfirm={goNextIfNoErrors} label="Enter the secret as text:" bind={[secretValue, setSecretValue]} /> @@ -82,10 +93,12 @@ export function SecretEditorScreen(): VNode { <div class="block"> Or upload a secret file <FileInput label="Choose file" onChange={setSecretFile} /> - {secretFile && <div> - Uploading secret file <b>{secretFile.name}</b> <a onClick={() => setSecretFile(undefined)}>cancel</a> - </div> - } + {secretFile && ( + <div> + Uploading secret file <b>{secretFile.name}</b>{" "} + <a onClick={() => setSecretFile(undefined)}>cancel</a> + </div> + )} </div> </AnastasisClientFrame> ); diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx index 61c66c8c8..556e3bdbf 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSetup.tsx @@ -26,6 +26,9 @@ export function AuthMethodEmailSetup({ : undefined; const errors = !email ? "Add your email" : emailError; + function goNextIfNoErrors(): void { + if (!errors) addEmailAuth(); + } return ( <AnastasisClientFrame hideNav title="Add email authentication"> <p> @@ -37,6 +40,7 @@ export function AuthMethodEmailSetup({ <EmailInput label="Email address" error={emailError} + onConfirm={goNextIfNoErrors} placeholder="email@domain.com" bind={[email, setEmail]} /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx index 1e0b6f18a..89017aa6f 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodEmailSolve.tsx @@ -10,7 +10,7 @@ import { AuthMethodSolveProps } from "./index"; export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { const [answer, setAnswer] = useState(""); - const [expanded, setExpanded] = useState(false) + const [expanded, setExpanded] = useState(false); const reducer = useAnastasisContext(); if (!reducer) { @@ -91,23 +91,38 @@ export function AuthMethodEmailSolve({ id }: AuthMethodSolveProps): VNode { <SolveOverviewFeedbackDisplay feedback={feedback} /> <p> An email has been sent to "<b>{selectedChallenge.instructions}</b>". The - message has and identification code and recovery code that starts with "<b>A-</b>". - Wait the message to arrive and the enter the recovery code below. + message has and identification code and recovery code that starts with " + <b>A-</b>". Wait the message to arrive and the enter the recovery code + below. </p> - {!expanded ? <p> - The identification code in the email should start with "{selectedUuid.substring(0, 10)}" - <span class="icon has-tooltip-top" data-tooltip="click to expand" onClick={() => setExpanded(e => !e)}> - <i class="mdi mdi-information" /> - </span> - </p> - : <p> - The identification code in the email is "{selectedUuid}" - <span class="icon has-tooltip-top" data-tooltip="click to show less code" onClick={() => setExpanded(e => !e)}> - <i class="mdi mdi-information" /> - </span> - </p>} - <TextInput label="Answer" + {!expanded ? ( + <p> + The identification code in the email should start with " + {selectedUuid.substring(0, 10)}" + <span + class="icon has-tooltip-top" + data-tooltip="click to expand" + onClick={() => setExpanded((e) => !e)} + > + <i class="mdi mdi-information" /> + </span> + </p> + ) : ( + <p> + The identification code in the email is "{selectedUuid}" + <span + class="icon has-tooltip-top" + data-tooltip="click to show less code" + onClick={() => setExpanded((e) => !e)} + > + <i class="mdi mdi-information" /> + </span> + </p> + )} + <TextInput + label="Answer" grabFocus + onConfirm={onNext} bind={[answer, setAnswer]} placeholder="A-1234567812345678" /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx index dee550e5b..501a40600 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodIbanSetup.tsx @@ -36,6 +36,9 @@ export function AuthMethodIbanSetup({ : !account ? "Add an account IBAN number" : undefined; + function goNextIfNoErrors(): void { + if (!errors) addIbanAuth(); + } return ( <AnastasisClientFrame hideNav title="Add bank transfer authentication"> <p> @@ -49,11 +52,13 @@ export function AuthMethodIbanSetup({ label="Bank account holder name" grabFocus placeholder="John Smith" + onConfirm={goNextIfNoErrors} bind={[name, setName]} /> <TextInput label="IBAN" placeholder="DE91100000000123456789" + onConfirm={goNextIfNoErrors} bind={[account, setAccount]} /> </div> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx index 6c8d36bcf..04e00500c 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSetup.tsx @@ -48,6 +48,10 @@ export function AuthMethodPostSetup({ : !country ? "The country is missing" : undefined; + + function goNextIfNoErrors(): void { + if (!errors) addPostAuth(); + } return ( <AnastasisClientFrame hideNav title="Add postal authentication"> <p> @@ -56,19 +60,40 @@ export function AuthMethodPostSetup({ will receive in a letter to that address. </p> <div> - <TextInput grabFocus label="Full Name" bind={[fullName, setFullName]} /> + <TextInput + grabFocus + label="Full Name" + bind={[fullName, setFullName]} + onConfirm={goNextIfNoErrors} + /> </div> <div> - <TextInput label="Street" bind={[street, setStreet]} /> + <TextInput + onConfirm={goNextIfNoErrors} + label="Street" + bind={[street, setStreet]} + /> </div> <div> - <TextInput label="City" bind={[city, setCity]} /> + <TextInput + onConfirm={goNextIfNoErrors} + label="City" + bind={[city, setCity]} + /> </div> <div> - <TextInput label="Postal Code" bind={[postcode, setPostcode]} /> + <TextInput + onConfirm={goNextIfNoErrors} + label="Postal Code" + bind={[postcode, setPostcode]} + /> </div> <div> - <TextInput label="Country" bind={[country, setCountry]} /> + <TextInput + onConfirm={goNextIfNoErrors} + label="Country" + bind={[country, setCountry]} + /> </div> {configured.length > 0 && ( diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx index 97e768cbe..bc56b9f2c 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodPostSolve.tsx @@ -89,7 +89,12 @@ export function AuthMethodPostSolve({ id }: AuthMethodSolveProps): VNode { <AnastasisClientFrame hideNav title="Postal Challenge"> <SolveOverviewFeedbackDisplay feedback={feedback} /> <p>Wait for the answer</p> - <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> + <TextInput + onConfirm={onNext} + label="Answer" + grabFocus + bind={[answer, setAnswer]} + /> <div style={{ diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx index 03725621c..19260c4ff 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSetup.tsx @@ -26,6 +26,9 @@ export function AuthMethodQuestionSetup({ : !answerText ? "Add the answer to your question" : undefined; + function goNextIfNoErrors(): void { + if (!errors) addQuestionAuth(); + } return ( <AnastasisClientFrame hideNav title="Add Security Question"> <div> @@ -39,6 +42,7 @@ export function AuthMethodQuestionSetup({ <TextInput label="Security question" grabFocus + onConfirm={goNextIfNoErrors} placeholder="Your question" bind={[questionText, setQuestionText]} /> @@ -46,6 +50,7 @@ export function AuthMethodQuestionSetup({ <div> <TextInput label="Answer" + onConfirm={goNextIfNoErrors} placeholder="Your answer" bind={[answerText, setAnswerText]} /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx index b4896eac8..2636ca47c 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodQuestionSolve.tsx @@ -91,11 +91,14 @@ export function AuthMethodQuestionSolve({ id }: AuthMethodSolveProps): VNode { <p> In this challenge you need to provide the answer for the next question: </p> - <pre> - {selectedChallenge.instructions} - </pre> + <pre>{selectedChallenge.instructions}</pre> <p>Type the answer below</p> - <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> + <TextInput + label="Answer" + onConfirm={onNext} + grabFocus + bind={[answer, setAnswer]} + /> <div style={{ diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx index 056b1b175..e70b2a53b 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSetup.tsx @@ -25,6 +25,9 @@ export function AuthMethodSmsSetup({ inputRef.current?.focus(); }, []); const errors = !mobileNumber ? "Add a mobile number" : undefined; + function goNextIfNoErrors(): void { + if (!errors) addSmsAuth(); + } return ( <AnastasisClientFrame hideNav title="Add SMS authentication"> <div> @@ -37,6 +40,7 @@ export function AuthMethodSmsSetup({ <PhoneNumberInput label="Mobile number" placeholder="Your mobile number" + onConfirm={goNextIfNoErrors} grabFocus bind={[mobileNumber, setMobileNumber]} /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx index 67049df12..218e8c858 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodSmsSolve.tsx @@ -11,7 +11,7 @@ import { AuthMethodSolveProps } from "./index"; export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { const [answer, setAnswer] = useState(""); - const [expanded, setExpanded] = useState(false) + const [expanded, setExpanded] = useState(false); const reducer = useAnastasisContext(); if (!reducer) { return ( @@ -91,23 +91,38 @@ export function AuthMethodSmsSolve({ id }: AuthMethodSolveProps): VNode { <SolveOverviewFeedbackDisplay feedback={feedback} /> <p> An sms has been sent to "<b>{selectedChallenge.instructions}</b>". The - message has and identification code and recovery code that starts with "<b>A-</b>". - Wait the message to arrive and the enter the recovery code below. + message has and identification code and recovery code that starts with " + <b>A-</b>". Wait the message to arrive and the enter the recovery code + below. </p> - {!expanded ? <p> - The identification code in the SMS should start with "{selectedUuid.substring(0, 10)}" - <span class="icon has-tooltip-top" data-tooltip="click to expand" onClick={() => setExpanded(e => !e)}> - <i class="mdi mdi-information" /> - </span> - </p> - : <p> - The identification code in the SMS is "{selectedUuid}" - <span class="icon has-tooltip-top" data-tooltip="click to show less code" onClick={() => setExpanded(e => !e)}> - <i class="mdi mdi-information" /> - </span> - </p>} - <TextInput label="Answer" + {!expanded ? ( + <p> + The identification code in the SMS should start with " + {selectedUuid.substring(0, 10)}" + <span + class="icon has-tooltip-top" + data-tooltip="click to expand" + onClick={() => setExpanded((e) => !e)} + > + <i class="mdi mdi-information" /> + </span> + </p> + ) : ( + <p> + The identification code in the SMS is "{selectedUuid}" + <span + class="icon has-tooltip-top" + data-tooltip="click to show less code" + onClick={() => setExpanded((e) => !e)} + > + <i class="mdi mdi-information" /> + </span> + </p> + )} + <TextInput + label="Answer" grabFocus + onConfirm={onNext} bind={[answer, setAnswer]} placeholder="A-1234567812345678" /> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx index 1451aadc8..6b0dd7a79 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSetup.tsx @@ -38,6 +38,9 @@ export function AuthMethodTotpSetup({ : !testCodeMatches ? "The test code doesnt match" : undefined; + function goNextIfNoErrors(): void { + if (!errors) addTotpAuth(); + } return ( <AnastasisClientFrame hideNav title="Add TOTP authentication"> <p> @@ -54,7 +57,11 @@ export function AuthMethodTotpSetup({ <p> After scanning the code with your TOTP App, test it in the input below. </p> - <TextInput label="Test code" bind={[test, setTest]} /> + <TextInput + label="Test code" + onConfirm={goNextIfNoErrors} + bind={[test, setTest]} + /> {configured.length > 0 && ( <section class="section"> <div class="block">Your TOTP numbers:</div> diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx index e9fa7012f..347f9bf03 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodTotpSolve.tsx @@ -89,7 +89,12 @@ export function AuthMethodTotpSolve({ id }: AuthMethodSolveProps): VNode { <AnastasisClientFrame hideNav title="TOTP Challenge"> <SolveOverviewFeedbackDisplay feedback={feedback} /> <p>enter the totp solution</p> - <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> + <TextInput + label="Answer" + onConfirm={onNext} + grabFocus + bind={[answer, setAnswer]} + /> <div style={{ diff --git a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx index 672b23500..04a129c4a 100644 --- a/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx +++ b/packages/anastasis-webui/src/pages/home/authMethod/AuthMethodVideoSetup.tsx @@ -20,6 +20,9 @@ export function AuthMethodVideoSetup({ }, }); }; + function goNextIfNoErrors(): void { + addVideoAuth(); + } return ( <AnastasisClientFrame hideNav title="Add video authentication"> <p> @@ -32,6 +35,7 @@ export function AuthMethodVideoSetup({ <ImageInput label="Choose photograph" grabFocus + onConfirm={goNextIfNoErrors} bind={[image, setImage]} /> </div> |