From 4c46c03b3bfbee20f990e8e6e68a6005fe0774bd Mon Sep 17 00:00:00 2001 From: shad Date: Sun, 14 Jun 2026 16:45:54 +0400 Subject: [PATCH] fix(app): hydrate tenantId/actor from /me on app boot when session exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The prior loop tightened Approvals.loadQueue to early-return when tenantId is null. But the standard 'user reloads page with cached session token' path didn't populate tenantId — it was only set during loginAs or the live-fetch path. Added one effect in App: when isAuthed && !tenantId, call api.ping which proxies to /api/v1/auth/me and pulls user_id + tenant_id + email into the store. This unblocks tenant-scoped surfaces (Approvals) after a page reload. --- src/App.tsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index 382940f..a195a50 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -50,6 +50,25 @@ export default function App() { } }, [isAuthed, scene, setScene]); + // Hydrate identity (tenantId, user_id, display_name) from /me whenever a + // session token exists but the store hasn't captured the identity yet. + // This covers the path "user reloads page with a valid sessionStorage + // token" — without this, tenant-scoped surfaces show empty. + useEffect(() => { + if (!isAuthed) return; + if (useApp.getState().tenantId) return; + void (async () => { + const ping = await import("./lib/api").then((m) => m.api.ping()); + if (ping.ok && ping.user_id) { + useApp.setState({ + actor: { mode: "direct_user", user_id: ping.user_id }, + userEmail: ping.user ?? useApp.getState().userEmail, + tenantId: ping.tenant_id ?? null, + }); + } + })(); + }, [isAuthed]); + useEffect(() => { if (mode === "live") startPolling(); return () => stopPolling();