diff options
Diffstat (limited to 'packages/challenger-ui')
-rw-r--r-- | packages/challenger-ui/src/Routing.tsx | 39 | ||||
-rw-r--r-- | packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx | 11 | ||||
-rw-r--r-- | packages/challenger-ui/src/hooks/session.ts | 28 | ||||
-rw-r--r-- | packages/challenger-ui/src/pages/AnswerChallenge.tsx | 24 | ||||
-rw-r--r-- | packages/challenger-ui/src/pages/AskChallenge.tsx | 98 | ||||
-rw-r--r-- | packages/challenger-ui/src/pages/CallengeCompleted.tsx | 3 |
6 files changed, 126 insertions, 77 deletions
diff --git a/packages/challenger-ui/src/Routing.tsx b/packages/challenger-ui/src/Routing.tsx index eae182be5..f1f4d82d2 100644 --- a/packages/challenger-ui/src/Routing.tsx +++ b/packages/challenger-ui/src/Routing.tsx @@ -44,6 +44,10 @@ export function Routing(): VNode { } const publicPages = { + noinfo: urlPattern<{ nonce: string }>( + /\/noinfo\/(?<nonce>[a-zA-Z0-9]+)/, + ({ nonce }) => `#/noinfo/${nonce}`, + ), authorize: urlPattern<{ nonce: string }>( /\/authorize\/(?<nonce>[a-zA-Z0-9]+)/, ({ nonce }) => `#/authorize/${nonce}`, @@ -93,6 +97,9 @@ function PublicRounting(): VNode { } switch (location.name) { + case "noinfo": { + return <div>no info</div>; + } case "setup": { return ( <Setup @@ -137,6 +144,13 @@ function PublicRounting(): VNode { <CheckChallengeIsUpToDate sessionId={sessionId} nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} onCompleted={() => { start(sessionId); navigateTo( @@ -170,6 +184,13 @@ function PublicRounting(): VNode { return ( <CheckChallengeIsUpToDate nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} onCompleted={() => { navigateTo( publicPages.completed.url({ @@ -196,6 +217,13 @@ function PublicRounting(): VNode { return ( <CheckChallengeIsUpToDate nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} onCompleted={() => { navigateTo( publicPages.completed.url({ @@ -219,7 +247,16 @@ function PublicRounting(): VNode { } case "completed": { return ( - <CheckChallengeIsUpToDate nonce={location.values.nonce}> + <CheckChallengeIsUpToDate + nonce={location.values.nonce} + onNoInfo={() => { + navigateTo( + publicPages.noinfo.url({ + nonce: location.values.nonce, + }), + ); + }} + > <CallengeCompleted nonce={location.values.nonce} /> </CheckChallengeIsUpToDate> ); diff --git a/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx b/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx index 04556696b..70e41bf1e 100644 --- a/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx +++ b/packages/challenger-ui/src/components/CheckChallengeIsUpToDate.tsx @@ -16,7 +16,7 @@ import { HttpStatusCode, TalerError, - assertUnreachable + assertUnreachable, } from "@gnu-taler/taler-util"; import { Attention, @@ -34,6 +34,7 @@ interface Props { onCompleted?: () => void; onChangeLeft?: () => void; onNoMoreChanges?: () => void; + onNoInfo: () => void; } export function CheckChallengeIsUpToDate({ sessionId: sessionFromParam, @@ -42,6 +43,7 @@ export function CheckChallengeIsUpToDate({ onCompleted, onChangeLeft, onNoMoreChanges, + onNoInfo, }: Props): VNode { const { state, updateStatus } = useSessionState(); const { i18n } = useTranslationContext(); @@ -57,12 +59,17 @@ export function CheckChallengeIsUpToDate({ }; const result = useChallengeSession(nonce, sessionId); + console.log("asd"); + if (!sessionId) { + onNoInfo(); + return <Loading />; + } if (!result) { return <Loading />; } if (result instanceof TalerError) { - return <div />; + return <pre>{JSON.stringify(result, undefined, 2)}</pre>; } if (result.type === "fail") { diff --git a/packages/challenger-ui/src/hooks/session.ts b/packages/challenger-ui/src/hooks/session.ts index 4d0ffeccf..ed7ea8986 100644 --- a/packages/challenger-ui/src/hooks/session.ts +++ b/packages/challenger-ui/src/hooks/session.ts @@ -45,9 +45,8 @@ export type LastChallengeResponse = { }; export type SessionState = SessionId & { - email: string | undefined; lastTry: LastChallengeResponse | undefined; - challengeStatus: ChallengerApi.ChallengeStatus | undefined; + lastStatus: ChallengerApi.ChallengeStatus | undefined; completedURL: string | undefined; }; export const codecForLastChallengeResponse = (): Codec<LastChallengeResponse> => @@ -63,15 +62,14 @@ export const codecForSessionState = (): Codec<SessionState> => .property("redirectURL", codecForStringURL()) .property("completedURL", codecOptional(codecForStringURL())) .property("state", codecForString()) - .property("challengeStatus", codecOptional(codecForChallengeStatus())) + .property("lastStatus", codecOptional(codecForChallengeStatus())) .property("lastTry", codecOptional(codecForLastChallengeResponse())) - .property("email", codecOptional(codecForString())) .build("SessionState"); export interface SessionStateHandler { state: SessionState | undefined; start(s: SessionId): void; - accepted(e: string, l: LastChallengeResponse): void; + accepted(l: LastChallengeResponse): void; completed(e: URL): void; updateStatus(s: ChallengerApi.ChallengeStatus): void; } @@ -96,16 +94,14 @@ export function useSessionState(): SessionStateHandler { ...info, lastTry: undefined, completedURL: undefined, - challengeStatus: undefined, - email: undefined, + lastStatus: undefined, }); cleanAllCache(); }, - accepted(email, lastTry) { + accepted(lastTry) { if (!state) return; update({ ...state, - email, lastTry, }); }, @@ -118,23 +114,23 @@ export function useSessionState(): SessionStateHandler { }, updateStatus(st: ChallengerApi.ChallengeStatus) { if (!state) return; - if (!state.challengeStatus) { + if (!state.lastStatus) { update({ ...state, - challengeStatus: st, + lastStatus: st, }); return; } // current status - const cu = state.challengeStatus; + const ls = state.lastStatus; if ( - cu.changes_left !== st.changes_left || - cu.fix_address !== st.fix_address || - cu.last_address !== st.last_address + ls.changes_left !== st.changes_left || + ls.fix_address !== st.fix_address || + ls.last_address !== st.last_address ) { update({ ...state, - challengeStatus: st, + lastStatus: st, }); return; } diff --git a/packages/challenger-ui/src/pages/AnswerChallenge.tsx b/packages/challenger-ui/src/pages/AnswerChallenge.tsx index bad6d70de..62b7e775d 100644 --- a/packages/challenger-ui/src/pages/AnswerChallenge.tsx +++ b/packages/challenger-ui/src/pages/AnswerChallenge.tsx @@ -16,7 +16,7 @@ import { ChallengerApi, HttpStatusCode, - assertUnreachable + assertUnreachable, } from "@gnu-taler/taler-util"; import { Attention, @@ -25,7 +25,7 @@ import { ShowInputErrorLabel, useChallengerApiContext, useLocalNotificationHandler, - useTranslationContext + useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; @@ -50,19 +50,25 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode { pin: !pin ? i18n.str`Can't be empty` : undefined, }); + const lastEmail = !state + ? undefined + : !state.lastStatus + ? undefined + : ((state.lastStatus.last_address as any)["email"] as string); + const onSendAgain = - !state || state.email === undefined + !state || lastEmail === undefined ? undefined : withErrorHandler( async () => { - if (!state?.email) return; - return await lib.bank.challenge(nonce, { email: state.email }); + if (!lastEmail) return; + return await lib.bank.challenge(nonce, { email: lastEmail }); }, (ok) => { if ("redirectURL" in ok.body) { completed(ok.body.redirectURL); } else { - accepted(state.email!, { + accepted({ attemptsLeft: ok.body.attempts_left, nextSend: ok.body.next_tx_time, transmitted: ok.body.transmitted, @@ -141,13 +147,13 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode { <p class="mt-2 text-lg leading-8 text-gray-600"> {state.lastTry.transmitted ? ( <i18n.Translate> - A TAN was sent to your address "{state.email}". + A TAN was sent to your address "{lastEmail}". </i18n.Translate> ) : ( <Attention title={i18n.str`Resend failed`} type="warning"> <i18n.Translate> We recently already sent a TAN to your address " - {state.email}". A new TAN will not be transmitted again + {lastEmail}". A new TAN will not be transmitted again before "{state.lastTry.nextSend}". </i18n.Translate> </Attention> @@ -227,7 +233,7 @@ export function AnswerChallenge({ nonce, onComplete }: Props): VNode { </form> </div> </Fragment> - ) + ); } export function undefinedIfEmpty<T extends object>(obj: T): T | undefined { diff --git a/packages/challenger-ui/src/pages/AskChallenge.tsx b/packages/challenger-ui/src/pages/AskChallenge.tsx index 813636fa4..76fe6f00a 100644 --- a/packages/challenger-ui/src/pages/AskChallenge.tsx +++ b/packages/challenger-ui/src/pages/AskChallenge.tsx @@ -13,9 +13,7 @@ You should have received a copy of the GNU General Public License along with GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> */ -import { - HttpStatusCode -} from "@gnu-taler/taler-util"; +import { HttpStatusCode } from "@gnu-taler/taler-util"; import { Attention, Button, @@ -24,7 +22,7 @@ import { ShowInputErrorLabel, useChallengerApiContext, useLocalNotificationHandler, - useTranslationContext + useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, VNode, h } from "preact"; import { useState } from "preact/hooks"; @@ -38,24 +36,22 @@ export const EMAIL_REGEX = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/; type Props = { nonce: string; onSendSuccesful: () => void; - routeSolveChallenge: RouteDefinition<{nonce:string}>, + routeSolveChallenge: RouteDefinition<{ nonce: string }>; }; -export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Props): VNode { +export function AskChallenge({ + nonce, + onSendSuccesful, + routeSolveChallenge, +}: Props): VNode { const { state, accepted, completed } = useSessionState(); - const status = state?.challengeStatus; + const status = state?.lastStatus; const prevEmail = - !status || !status.last_address - ? undefined - : ((status.last_address as any)["email"] as string); + !status || !status.last_address ? undefined : status.last_address["email"]; const regexEmail = !status || !status.restrictions ? undefined - : ((status.restrictions as any)["email"] as { - regex?: string; - hint?: string; - hint_i18n?: string; - }); + : status.restrictions["email"]; const { lib } = useChallengerApiContext(); const { i18n } = useTranslationContext(); @@ -82,37 +78,39 @@ export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Pro : undefined, }); - const onSend = errors? undefined : withErrorHandler( - async () => { - return lib.bank.challenge(nonce, { email: email! }); - }, - (ok) => { - if ("redirectURL" in ok.body) { - completed(ok.body.redirectURL); - } else { - accepted(email!, { - attemptsLeft: ok.body.attempts_left, - nextSend: ok.body.next_tx_time, - transmitted: ok.body.transmitted, - }); - } - onSendSuccesful(); - }, - (fail) => { - switch (fail.case) { - case HttpStatusCode.BadRequest: - return i18n.str``; - case HttpStatusCode.NotFound: - return i18n.str``; - case HttpStatusCode.NotAcceptable: - return i18n.str``; - case HttpStatusCode.TooManyRequests: - return i18n.str``; - case HttpStatusCode.InternalServerError: - return i18n.str``; - } - }, - ); + const onSend = errors + ? undefined + : withErrorHandler( + async () => { + return lib.bank.challenge(nonce, { email: email! }); + }, + (ok) => { + if ("redirectURL" in ok.body) { + completed(ok.body.redirectURL); + } else { + accepted({ + attemptsLeft: ok.body.attempts_left, + nextSend: ok.body.next_tx_time, + transmitted: ok.body.transmitted, + }); + } + onSendSuccesful(); + }, + (fail) => { + switch (fail.case) { + case HttpStatusCode.BadRequest: + return i18n.str``; + case HttpStatusCode.NotFound: + return i18n.str``; + case HttpStatusCode.NotAcceptable: + return i18n.str``; + case HttpStatusCode.TooManyRequests: + return i18n.str``; + case HttpStatusCode.InternalServerError: + return i18n.str``; + } + }, + ); if (!status) { return <div>no status loaded</div>; @@ -136,9 +134,13 @@ export function AskChallenge({ nonce, onSendSuccesful,routeSolveChallenge }: Pro </div> {state.lastTry && ( <Fragment> - <Attention title={i18n.str`A code has been sent to ${state.email}`}> + <Attention title={i18n.str`A code has been sent to ${prevEmail}`}> <i18n.Translate> - You can change the destination or <a href={routeSolveChallenge.url({nonce })}><i18n.Translate>complete the challenge here</i18n.Translate></a>. + You can change the destination or{" "} + <a href={routeSolveChallenge.url({ nonce })}> + <i18n.Translate>complete the challenge here</i18n.Translate> + </a> + . </i18n.Translate> </Attention> </Fragment> diff --git a/packages/challenger-ui/src/pages/CallengeCompleted.tsx b/packages/challenger-ui/src/pages/CallengeCompleted.tsx index 24a05c67f..f8cd7ce60 100644 --- a/packages/challenger-ui/src/pages/CallengeCompleted.tsx +++ b/packages/challenger-ui/src/pages/CallengeCompleted.tsx @@ -19,7 +19,8 @@ type Props = { nonce: string; } export function CallengeCompleted({nonce}:Props):VNode { + return <div> - completed + completed {nonce} </div> }
\ No newline at end of file |