taler-typescript-core

Wallet core logic and WebUIs for various components
Log | Files | Refs | Submodules | README | LICENSE

commit 326d942d9634ee5f2a7b7874be06bc6c8ece167a
parent b8df370f71a002b50adf38820a04cbf813a71515
Author: Sebastian <sebasjm@gmail.com>
Date:   Thu,  9 Oct 2025 14:22:23 -0300

fixes #10250 support new info

Diffstat:
Mpackages/bank-ui/src/pages/SolveMFA.tsx | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 56 insertions(+), 12 deletions(-)

diff --git a/packages/bank-ui/src/pages/SolveMFA.tsx b/packages/bank-ui/src/pages/SolveMFA.tsx @@ -1,4 +1,5 @@ import { + AbsoluteTime, Challenge, ChallengeResponse, HttpStatusCode, @@ -19,10 +20,8 @@ import { useTranslationContext, } from "@gnu-taler/web-util/browser"; import { Fragment, h, VNode } from "preact"; -import { useState } from "preact/hooks"; -import { useSessionState } from "../hooks/session.js"; +import { useState, useEffect } from "preact/hooks"; import { doAutoFocus } from "./PaytoWireTransferForm.js"; -import { AbsoluteTime } from "@gnu-taler/taler-util"; export interface Props { onCompleted(challenges: string[]): Promise<NotificationMessage | undefined>; @@ -37,9 +36,11 @@ function SolveChallenge({ onCancel, onSolved, username, + expiration, }: { onCancel: () => void; challenge: Challenge; + expiration: AbsoluteTime; onSolved: () => void; username: string; }): VNode { @@ -50,10 +51,26 @@ function SolveChallenge({ } = useBankCoreApiContext(); const [notification, notifyOnError] = useLocalNotificationBetter(); + const [showExpired, setExpired] = useState( + expiration !== undefined && AbsoluteTime.isExpired(expiration), + ); + const errors = undefinedIfEmpty({ code: !tanCode ? i18n.str`Required` : undefined, }); + useEffect(() => { + if (showExpired) return; + const remain = AbsoluteTime.remaining(expiration).d_ms; + if (remain === "forever") return; + const handler = setTimeout(() => { + setExpired(true); + }, remain); + return () => { + clearTimeout(handler); + }; + }, []); + const doVerification = !tanCode ? undefined : notifyOnError( @@ -162,6 +179,23 @@ function SolveChallenge({ </div> </div> </form> + {expiration.t_ms === "never" ? undefined : ( + <p class="text-gray-400 text-sm mt-2"> + <i18n.Translate> + It will expired at{" "} + <Time format="HH:mm" timestamp={expiration} /> + </i18n.Translate> + </p> + )} + {showExpired ? ( + <p class="text-sm"> + <i18n.Translate> + The challenge is expired and can't be solved but you can go + back and create a new challenge. + </i18n.Translate> + </p> + ) : undefined} + <div class="mt-6 mb-4 flex justify-between"> <button type="button" @@ -198,7 +232,10 @@ export function SolveMFAChallenges({ const { i18n } = useTranslationContext(); const [solved, setSolved] = useState<string[]>([]); - const [selected, setSelected] = useState<Challenge>(); + const [selected, setSelected] = useState<{ + ch: Challenge; + expiration: AbsoluteTime; + }>(); const [notification, notifyOnError] = useLocalNotificationBetter(); const { lib: { bank: api }, @@ -216,11 +253,12 @@ export function SolveMFAChallenges({ return ( <SolveChallenge onCancel={() => setSelected(undefined)} - challenge={selected} + challenge={selected.ch} + expiration={selected.expiration} username={username} onSolved={() => { setSelected(undefined); - setSolved([...solved, selected.challenge_id]); + setSolved([...solved, selected.ch.challenge_id]); }} /> ); @@ -247,7 +285,12 @@ export function SolveMFAChallenges({ // ), }); } - setSelected(ch); + setSelected({ + ch, + expiration: !success.body.solve_expiration + ? AbsoluteTime.never() + : AbsoluteTime.fromProtocolTimestamp(success.body.solve_expiration), + }); }, (fail) => { switch (fail.case) { @@ -328,10 +371,8 @@ export function SolveMFAChallenges({ </span> </h2> {currentChallenge.challenges.map((challenge) => { - const time = AbsoluteTime.now(); - const alreadySent = AbsoluteTime.isExpired(time); - // const time = retransmission[challenge.tan_channel]; - // const alreadySent = !AbsoluteTime.isExpired(time); + const time = retransmission[challenge.tan_channel]; + const alreadySent = !AbsoluteTime.isExpired(time); const noNeedToComplete = hasSolvedEnough || solved.indexOf(challenge.challenge_id) !== -1; @@ -339,7 +380,10 @@ export function SolveMFAChallenges({ const doSelect = noNeedToComplete ? undefined : async () => { - setSelected(challenge); + setSelected({ + ch: challenge, + expiration: AbsoluteTime.never(), + }); }; const doSend =