diff options
author | Florian Dold <florian@dold.me> | 2021-11-03 18:56:19 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-11-03 18:56:26 +0100 |
commit | 9fb6536fbc91adaf7a8a80860fcef5e1f80bfb3b (patch) | |
tree | 0febbc9439784f57eaa2947e2494b2ece35fe34b /packages/anastasis-webui | |
parent | fefdb0d7adcfe95be20f4ff81af316a0ca64f35a (diff) |
anastasis-webui: show feedback in solution screen
Diffstat (limited to 'packages/anastasis-webui')
-rw-r--r-- | packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx | 4 | ||||
-rw-r--r-- | packages/anastasis-webui/src/pages/home/SolveScreen.tsx | 177 |
2 files changed, 135 insertions, 46 deletions
diff --git a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx index 69dbce037..7bafbe06a 100644 --- a/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/ChallengeOverviewScreen.tsx @@ -5,7 +5,7 @@ import { useAnastasisContext } from "../../context/anastasis"; import { AnastasisClientFrame } from "./index"; import { authMethods, KnownAuthMethods } from "./authMethod"; -function FeedbackDisplay(props: { feedback?: ChallengeFeedback }) { +function OverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) { const { feedback } = props; if (!feedback) { return null; @@ -130,7 +130,7 @@ export function ChallengeOverviewScreen(): VNode { <span class="icon">{method?.icon}</span> <span>{info.instructions}</span> </div> - <FeedbackDisplay feedback={info.feedback} /> + <OverviewFeedbackDisplay feedback={info.feedback} /> </div> <div> {method && info.feedback?.state !== "solved" ? ( diff --git a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx index b0cfa9bb0..d4d9271b4 100644 --- a/packages/anastasis-webui/src/pages/home/SolveScreen.tsx +++ b/packages/anastasis-webui/src/pages/home/SolveScreen.tsx @@ -1,38 +1,89 @@ import { Fragment, h, VNode } from "preact"; import { useState } from "preact/hooks"; import { AnastasisClientFrame } from "."; -import { ChallengeFeedback, ChallengeInfo } from "../../../../anastasis-core/lib"; +import { + ChallengeFeedback, + ChallengeFeedbackStatus, + ChallengeInfo, +} from "../../../../anastasis-core/lib"; import { TextInput } from "../../components/fields/TextInput"; import { useAnastasisContext } from "../../context/anastasis"; +function SolveOverviewFeedbackDisplay(props: { feedback?: ChallengeFeedback }) { + const { feedback } = props; + if (!feedback) { + return null; + } + switch (feedback.state) { + case ChallengeFeedbackStatus.Message: + return ( + <div> + <p>{feedback.message}</p> + </div> + ); + case ChallengeFeedbackStatus.Pending: + case ChallengeFeedbackStatus.AuthIban: + return null; + case ChallengeFeedbackStatus.RateLimitExceeded: + return <div>Rate limit exceeded.</div>; + case ChallengeFeedbackStatus.Redirect: + return <div>Redirect (FIXME: not supported)</div>; + case ChallengeFeedbackStatus.Unsupported: + return <div>Challenge not supported by client.</div>; + case ChallengeFeedbackStatus.TruthUnknown: + return <div>Truth unknown</div>; + default: + return ( + <div> + <pre>{JSON.stringify(feedback)}</pre> + </div> + ); + } +} + export function SolveScreen(): VNode { - const reducer = useAnastasisContext() + const reducer = useAnastasisContext(); const [answer, setAnswer] = useState(""); if (!reducer) { - return <AnastasisClientFrame hideNav title="Recovery problem"> - <div>no reducer in context</div> - </AnastasisClientFrame> + return ( + <AnastasisClientFrame hideNav title="Recovery problem"> + <div>no reducer in context</div> + </AnastasisClientFrame> + ); } - if (!reducer.currentReducerState || reducer.currentReducerState.recovery_state === undefined) { - return <AnastasisClientFrame hideNav title="Recovery problem"> - <div>invalid state</div> - </AnastasisClientFrame> + if ( + !reducer.currentReducerState || + reducer.currentReducerState.recovery_state === undefined + ) { + return ( + <AnastasisClientFrame hideNav title="Recovery problem"> + <div>invalid state</div> + </AnastasisClientFrame> + ); } if (!reducer.currentReducerState.recovery_information) { - return <AnastasisClientFrame hideNext="Recovery document not found" title="Recovery problem"> - <div>no recovery information found</div> - </AnastasisClientFrame> + return ( + <AnastasisClientFrame + hideNext="Recovery document not found" + title="Recovery problem" + > + <div>no recovery information found</div> + </AnastasisClientFrame> + ); } if (!reducer.currentReducerState.selected_challenge_uuid) { - return <AnastasisClientFrame hideNav title="Recovery problem"> - <div>invalid state</div> - </AnastasisClientFrame> + return ( + <AnastasisClientFrame hideNav title="Recovery problem"> + <div>invalid state</div> + </AnastasisClientFrame> + ); } const chArr = reducer.currentReducerState.recovery_information.challenges; - const challengeFeedback = reducer.currentReducerState.challenge_feedback ?? {}; + const challengeFeedback = + reducer.currentReducerState.challenge_feedback ?? {}; const selectedUuid = reducer.currentReducerState.selected_challenge_uuid; const challenges: { [uuid: string]: ChallengeInfo; @@ -47,31 +98,44 @@ export function SolveScreen(): VNode { email: SolveEmailEntry, post: SolvePostEntry, }; - const SolveDialog = selectedChallenge === undefined ? SolveUndefinedEntry : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry; + const SolveDialog = + selectedChallenge === undefined + ? SolveUndefinedEntry + : dialogMap[selectedChallenge.type] ?? SolveUnsupportedEntry; function onNext(): void { - reducer?.transition("solve_challenge", { answer }) + reducer?.transition("solve_challenge", { answer }); } function onCancel(): void { - reducer?.back() + reducer?.back(); } - return ( - <AnastasisClientFrame - hideNav - title="Recovery: Solve challenge" - > + <AnastasisClientFrame hideNav title="Recovery: Solve challenge"> + <SolveOverviewFeedbackDisplay + feedback={challengeFeedback[selectedUuid]} + /> <SolveDialog id={selectedUuid} answer={answer} setAnswer={setAnswer} challenge={selectedChallenge} - feedback={challengeFeedback[selectedUuid]} /> + feedback={challengeFeedback[selectedUuid]} + /> - <div style={{ marginTop: '2em', display: 'flex', justifyContent: 'space-between' }}> - <button class="button" onClick={onCancel}>Cancel</button> - <button class="button is-info" onClick={onNext} >Confirm</button> + <div + style={{ + marginTop: "2em", + display: "flex", + justifyContent: "space-between", + }} + > + <button class="button" onClick={onCancel}> + Cancel + </button> + <button class="button is-info" onClick={onNext}> + Confirm + </button> </div> </AnastasisClientFrame> ); @@ -85,38 +149,61 @@ export interface SolveEntryProps { setAnswer: (s: string) => void; } -function SolveSmsEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode { - return (<Fragment> - <p>An sms has been sent to "<b>{challenge.instructions}</b>". Type the code below</p> - <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> - </Fragment> +function SolveSmsEntry({ + challenge, + answer, + setAnswer, +}: SolveEntryProps): VNode { + return ( + <Fragment> + <p> + An sms has been sent to "<b>{challenge.instructions}</b>". Type the code + below + </p> + <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> + </Fragment> ); } -function SolveQuestionEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode { +function SolveQuestionEntry({ + challenge, + answer, + setAnswer, +}: SolveEntryProps): VNode { return ( <Fragment> <p>Type the answer to the following question:</p> - <pre> - {challenge.instructions} - </pre> + <pre>{challenge.instructions}</pre> <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> </Fragment> ); } -function SolvePostEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode { +function SolvePostEntry({ + challenge, + answer, + setAnswer, +}: SolveEntryProps): VNode { return ( <Fragment> - <p>instruction for post type challenge "<b>{challenge.instructions}</b>"</p> + <p> + instruction for post type challenge "<b>{challenge.instructions}</b>" + </p> <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> </Fragment> ); } -function SolveEmailEntry({ challenge, answer, setAnswer }: SolveEntryProps): VNode { +function SolveEmailEntry({ + challenge, + answer, + setAnswer, +}: SolveEntryProps): VNode { return ( <Fragment> - <p>An email has been sent to "<b>{challenge.instructions}</b>". Type the code below</p> + <p> + An email has been sent to "<b>{challenge.instructions}</b>". Type the + code below + </p> <TextInput label="Answer" grabFocus bind={[answer, setAnswer]} /> </Fragment> ); @@ -126,7 +213,8 @@ function SolveUnsupportedEntry(props: SolveEntryProps): VNode { return ( <Fragment> <p> - The challenge selected is not supported for this UI. Please update this version or try using another policy. + The challenge selected is not supported for this UI. Please update this + version or try using another policy. </p> <p> <b>Challenge type:</b> {props.challenge.type} @@ -136,9 +224,10 @@ function SolveUnsupportedEntry(props: SolveEntryProps): VNode { } function SolveUndefinedEntry(props: SolveEntryProps): VNode { return ( - <Fragment > + <Fragment> <p> - There is no challenge information for id <b>"{props.id}"</b>. Try resetting the recovery session. + There is no challenge information for id <b>"{props.id}"</b>. Try + resetting the recovery session. </p> </Fragment> ); |