diff options
Diffstat (limited to 'packages/challenger-ui/src/pages/AskChallenge.tsx')
-rw-r--r-- | packages/challenger-ui/src/pages/AskChallenge.tsx | 138 |
1 files changed, 44 insertions, 94 deletions
diff --git a/packages/challenger-ui/src/pages/AskChallenge.tsx b/packages/challenger-ui/src/pages/AskChallenge.tsx index 71f45dde3..675e2b869 100644 --- a/packages/challenger-ui/src/pages/AskChallenge.tsx +++ b/packages/challenger-ui/src/pages/AskChallenge.tsx @@ -14,24 +14,20 @@ GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ import { + HttpStatusCode +} from "@gnu-taler/taler-util"; +import { Attention, Button, - Loading, LocalNotificationBanner, + RouteDefinition, ShowInputErrorLabel, useChallengerApiContext, useLocalNotificationHandler, - useTranslationContext, + useTranslationContext } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; -import { useChallengeSession } from "../hooks/challenge.js"; -import { - ChallengerApi, - HttpStatusCode, - TalerError, - assertUnreachable, -} from "@gnu-taler/taler-util"; import { useSessionState } from "../hooks/session.js"; type Form = { @@ -42,33 +38,29 @@ export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/; type Props = { nonce: string; onSendSuccesful: () => void; + routeSolveChallenge: RouteDefinition<{nonce:string}>, }; -function ChallengeForm({ - nonce, - status, - onSendSuccesful, -}: { - nonce: string; - status: ChallengerApi.ChallengeStatus; - onSendSuccesful: () => void; -}): VNode { - const prevEmail = !status.last_address - ? undefined - : ((status.last_address as any)["email"] as string); - const regexEmail = !status.restrictions - ? undefined - : ((status.restrictions as any)["email"] as { - regex?: string; - hint?: string; - hint_i18n?: string; - }); +export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Props): VNode { + const { state, accepted, completed } = useSessionState(); + const status = state?.challengeStatus; + const prevEmail = + !status || !status.last_address + ? undefined + : ((status.last_address as any)["email"] as string); + const regexEmail = + !status || !status.restrictions + ? undefined + : ((status.restrictions as any)["email"] as { + regex?: string; + hint?: string; + hint_i18n?: string; + }); const { lib } = useChallengerApiContext(); const { i18n } = useTranslationContext(); const [notification, withErrorHandler] = useLocalNotificationHandler(); const [email, setEmail] = useState<string | undefined>(prevEmail); - const { accepted, completed } = useSessionState(); const [repeat, setRepeat] = useState<string | undefined>(); const errors = undefinedIfEmpty({ @@ -82,10 +74,12 @@ function ChallengeForm({ : undefined : !EMAIL_REGEX.test(email) ? i18n.str`invalid email` - : email !== repeat - ? i18n.str`emails don't match` - : undefined, - repeat: !repeat ? i18n.str`required` : undefined, + : undefined, + repeat: !repeat + ? i18n.str`required` + : email !== repeat + ? i18n.str`emails doesn't match` + : undefined, }); const onSend = withErrorHandler( @@ -120,6 +114,10 @@ function ChallengeForm({ }, ); + if (!status) { + return <div>no status loaded</div>; + } + return ( <Fragment> <LocalNotificationBanner notification={notification} /> @@ -136,6 +134,15 @@ function ChallengeForm({ </i18n.Translate> </p> </div> + {state.lastTry && ( + <Fragment> + <Attention title={i18n.str`A code has been sent to ${state.email}`}> + <i18n.Translate> + You can change the destination or <a href={routeSolveChallenge.url({nonce })}><i18n.Translate>complete the challenge here</i18n.Translate></a>. + </i18n.Translate> + </Attention> + </Fragment> + )} <form method="POST" class="mx-auto mt-16 max-w-xl sm:mt-20" @@ -191,6 +198,10 @@ function ChallengeForm({ autocomplete="email" class="block w-full rounded-md border-0 px-3.5 py-2 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 sm:text-sm sm:leading-6" /> + <ShowInputErrorLabel + message={errors?.repeat} + isDirty={repeat !== undefined} + /> </div> </div> @@ -217,67 +228,6 @@ function ChallengeForm({ ); } -export function AskChallenge({ nonce, onSendSuccesful }: Props): VNode { - const { i18n } = useTranslationContext(); - const { state } = useSessionState(); - - const result = useChallengeSession(nonce, state); - - if (!result) { - return <Loading />; - } - if (result instanceof TalerError) { - return <div />; - } - - if (result.type === "fail") { - switch (result.case) { - case HttpStatusCode.BadRequest: { - return ( - <Attention type="danger" title={i18n.str`Bad request`}> - <i18n.Translate> - Could not start the challenge, check configuration. - </i18n.Translate> - </Attention> - ); - } - case HttpStatusCode.NotFound: { - return ( - <Attention type="danger" title={i18n.str`Not found`}> - <i18n.Translate>Nonce not found</i18n.Translate> - </Attention> - ); - } - case HttpStatusCode.NotAcceptable: { - return ( - <Attention type="danger" title={i18n.str`Not acceptable`}> - <i18n.Translate> - Server has wrong template configuration - </i18n.Translate> - </Attention> - ); - } - case HttpStatusCode.InternalServerError: { - return ( - <Attention type="danger" title={i18n.str`Internal error`}> - <i18n.Translate>Check logs</i18n.Translate> - </Attention> - ); - } - default: - assertUnreachable(result); - } - } - - return ( - <ChallengeForm - nonce={nonce} - status={result.body} - onSendSuccesful={onSendSuccesful} - /> - ); -} - export function undefinedIfEmpty<T extends object>(obj: T): T | undefined { return Object.keys(obj).some( (k) => (obj as Record<string, T>)[k] !== undefined, |