From c0b188411aa83f04939796725e8428ffc5d3e734 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:24:42 +0000 Subject: [PATCH 1/4] Keep signed-out food logs neutral Start with a neutral sign-in state and wait for the authenticated identity event before loading private food logs. --- frontend/components/FoodSearchPlaceholder.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index e1fe0ba..9514250 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -206,7 +206,7 @@ export function FoodSearchPlaceholder() { const [isClearingAll, setIsClearingAll] = useState(false); const [selectedLogId, setSelectedLogId] = useState(null); const [error, setError] = useState(null); - const [logError, setLogError] = useState(null); + const [logError, setLogError] = useState(SIGN_IN_REQUIRED_LOG_MESSAGE); const [didSearch, setDidSearch] = useState(false); const [searchStatus, setSearchStatus] = useState(null); @@ -337,10 +337,6 @@ export function FoodSearchPlaceholder() { } }, [clearPrivateLogState]); - useEffect(() => { - fetchLogs(); - }, [fetchLogs]); - useEffect(() => { return () => { searchAbortControllerRef.current?.abort(); From 2a8accdc1b7e08be86957df02f4715fcd80cc103 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:26:25 +0000 Subject: [PATCH 2/4] Announce authenticated state after identity restore Emit one authenticated event from refreshCurrentUser so private food logs load only after identity is confirmed, without duplicate reloads. --- frontend/components/XamanLoginPanel.tsx | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index 24705e5..dc8ec23 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -364,6 +364,7 @@ export function XamanLoginPanel() { } const data = (await response.json()) as MeResponse; setCurrentUser(data); + announceAuthState(true); return data; } catch { setCurrentUser(null); @@ -418,8 +419,6 @@ export function XamanLoginPanel() { if (cancelled) { return; } - - announceAuthState(true); setSuccessNotice( "Sign-in completed. Your session was restored in this browser." ); @@ -552,7 +551,6 @@ export function XamanLoginPanel() { } embeddedLoginStart.current = null; - announceAuthState(true); setError(null); setLoginStatus(null); setIsLoading(false); @@ -747,8 +745,6 @@ export function XamanLoginPanel() { if (!restoredUser) { throw new Error("Restored session was unavailable"); } - - announceAuthState(true); setSuccessNotice( "Sign-in completed. This original CalorieApp tab is signed in too." ); From 624d2560bf40b7890e12939bc4203ffbc82209a2 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:35:21 +0000 Subject: [PATCH 3/4] Add AbortSignal to refreshCurrentUser function Bind identity refreshes to their owning login or bridge lifecycle before announcing global auth state. --- frontend/components/XamanLoginPanel.tsx | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/components/XamanLoginPanel.tsx b/frontend/components/XamanLoginPanel.tsx index dc8ec23..0289a25 100644 --- a/frontend/components/XamanLoginPanel.tsx +++ b/frontend/components/XamanLoginPanel.tsx @@ -350,10 +350,11 @@ export function XamanLoginPanel() { const embeddedRequestId = useRef(""); const embeddedLoginStart = useRef(null); - const refreshCurrentUser = useCallback(async (): Promise => { + const refreshCurrentUser = useCallback(async (signal?: AbortSignal): Promise => { try { const response = await backendRequest( - `${BACKEND_BASE_URL}/api/identity/me` + `${BACKEND_BASE_URL}/api/identity/me`, + { signal } ); if (!response.ok) { setCurrentUser(null); @@ -367,6 +368,9 @@ export function XamanLoginPanel() { announceAuthState(true); return data; } catch { + if (signal?.aborted) { + return null; + } setCurrentUser(null); return null; } @@ -378,7 +382,7 @@ export function XamanLoginPanel() { loginAbortController.current = controller; async function restoreLogin() { - const user = await refreshCurrentUser(); + const user = await refreshCurrentUser(controller.signal); if (cancelled || controller.signal.aborted) { return; } @@ -412,7 +416,7 @@ export function XamanLoginPanel() { ); clearPendingLogin(); - const restoredUser = await refreshCurrentUser(); + const restoredUser = await refreshCurrentUser(controller.signal); if (!restoredUser) { throw new Error("Restored session was unavailable"); } @@ -447,6 +451,7 @@ export function XamanLoginPanel() { }, [refreshCurrentUser]); useEffect(() => { + const bridgeController = new AbortController(); let origin = trustedParentOrigin(); parentOrigin.current = origin; setIsEmbedded(origin !== null); @@ -545,7 +550,7 @@ export function XamanLoginPanel() { throw new Error(`Callback failed with ${response.status}`); } - const restoredUser = await refreshCurrentUser(); + const restoredUser = await refreshCurrentUser(bridgeController.signal); if (!restoredUser) { throw new Error("CalorieApp session was unavailable"); } @@ -586,6 +591,7 @@ export function XamanLoginPanel() { window.addEventListener("message", handleParentMessage); window.parent.postMessage({ type: "calorieapp:bridge:ready" }, "*"); return () => { + bridgeController.abort(); resizeObserver?.disconnect(); window.removeEventListener("message", handleParentMessage); }; @@ -741,7 +747,7 @@ export function XamanLoginPanel() { ); clearPendingLogin(); - const restoredUser = await refreshCurrentUser(); + const restoredUser = await refreshCurrentUser(controller.signal); if (!restoredUser) { throw new Error("Restored session was unavailable"); } From 909b6afc3d2abe7214173de01a009c9802293f32 Mon Sep 17 00:00:00 2001 From: xrpbanks <126300068+xrpbanks@users.noreply.github.com> Date: Sat, 29 Aug 2026 23:36:09 +0000 Subject: [PATCH 4/4] Clear signed-out prompt while logs load Remove the signed-out status as soon as authenticated log loading begins; restore it on a 401 response. --- frontend/components/FoodSearchPlaceholder.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/components/FoodSearchPlaceholder.tsx b/frontend/components/FoodSearchPlaceholder.tsx index 9514250..667364c 100644 --- a/frontend/components/FoodSearchPlaceholder.tsx +++ b/frontend/components/FoodSearchPlaceholder.tsx @@ -303,6 +303,7 @@ export function FoodSearchPlaceholder() { const requestId = ++logsRequestIdRef.current; setIsLogsLoading(true); + setLogError(null); try { const response = await backendRequest(`${BACKEND_BASE_URL}/logs`); if (requestId !== logsRequestIdRef.current) {