taler-typescript-core

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

commit ad25cd31f829eb012a1f8cfa0e89065d00738ccd
parent fa01e5b4dc7a230d858cebaa0fda87bc28bacc19
Author: Sebastian <sebasjm@taler-systems.com>
Date:   Wed, 22 Jul 2026 15:59:05 -0300

doUpdate is using stale data from anastasisState, using callback form in setAnastasisStateInternal to use an up-to-date previous state

Diffstat:
Mpackages/anastasis-webui/src/hooks/use-anastasis-reducer.ts | 91++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts b/packages/anastasis-webui/src/hooks/use-anastasis-reducer.ts @@ -186,6 +186,48 @@ function getStateFromStorage(): any { return state ?? undefined; } +async function tryUpdateProviders( + prevState: AnastasisState, + newState: AnastasisState, +): Promise<undefined | AnastasisState> { + const reducerState = newState.reducerState; + if ( + reducerState?.reducer_type !== "backup" && + reducerState?.reducer_type !== "recovery" + ) { + return undefined; + } + const provMap = reducerState.authentication_providers; + if (!provMap) { + return undefined; + } + const doUpdate = async (): Promise<undefined | AnastasisState> => { + const updates = await completeProviderStatus(provMap); + if (Object.keys(updates).length === 0) { + return; + } + const rs2 = reducerState; + if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") { + return; + } + const updated: AnastasisState = { + ...prevState, + reducerState: { + ...rs2, + authentication_providers: { + ...rs2.authentication_providers, + ...updates, + }, + }, + }; + return updated; + }; + return doUpdate().catch((e) => { + console.log("ERROR doUpdate", e); + return undefined; + }); +} + export function useAnastasisReducer(): AnastasisReducerApi { const [anastasisState, setAnastasisStateInternal] = useState<AnastasisState>( () => ({ @@ -206,44 +248,21 @@ export function useAnastasisReducer(): AnastasisReducerApi { } catch (e) { console.log("ERROR setAnastasisState", e); } - setAnastasisStateInternal(newState); - - const tryUpdateProviders = () => { - const reducerState = newState.reducerState; - if ( - reducerState?.reducer_type !== "backup" && - reducerState?.reducer_type !== "recovery" - ) { - return; - } - const provMap = reducerState.authentication_providers; - if (!provMap) { - return; - } - const doUpdate = async () => { - const updates = await completeProviderStatus(provMap); - if (Object.keys(updates).length === 0) { - return; - } - const rs2 = reducerState; - if (rs2.reducer_type !== "backup" && rs2.reducer_type !== "recovery") { - return; + setAnastasisStateInternal(prevState => { + tryUpdateProviders(prevState, newState).then(result => { + if (result) { + // FIXME + // there is a missing clear loop cut + // the will end because completeProviderStatus returns an + // empty list after contacting all providers, but is not clear + // and fragile + setAnastasisState(result) } - setAnastasisState({ - ...anastasisState, - reducerState: { - ...rs2, - authentication_providers: { - ...rs2.authentication_providers, - ...updates, - }, - }, - }); - }; - doUpdate().catch((e) => console.log("ERROR doUpdate", e)); - }; + }) + return newState + }); - tryUpdateProviders(); + ; }; async function doTransition(action: string, args: any): Promise<void> {