import { useEffect } from 'react'; import { useLogto } from '@logto/react'; import { Spinner } from '@cameleer/design-system'; import { useMe } from '../api/hooks'; import { useOrgStore } from './useOrganization'; import { fetchConfig } from '../config'; /** * Fetches /api/me and populates the org store with tenant-to-org mapping. * Also reads OAuth2 scopes from the access token and stores them. * Renders children once resolved. */ export function OrgResolver({ children }: { children: React.ReactNode }) { const { data: me, isLoading, isError } = useMe(); const { getAccessToken } = useLogto(); const { setOrganizations, setCurrentOrg, setScopes, currentOrgId } = useOrgStore(); // Effect 1: Org population — runs when /api/me data loads useEffect(() => { if (!me) return; // Map tenants: logtoOrgId is the org ID for token scoping, id is the DB UUID const orgEntries = me.tenants.map((t) => ({ id: t.logtoOrgId, name: t.name, slug: t.slug, tenantId: t.id, })); setOrganizations(orgEntries); // Auto-select if single tenant and no org selected yet if (orgEntries.length === 1 && !currentOrgId) { setCurrentOrg(orgEntries[0].id); } }, [me]); // Effect 2: Scope fetching — runs when me loads OR when currentOrgId changes useEffect(() => { if (!me) return; // Read scopes from a single access token (org-scoped when an org is selected, // global otherwise). Logto merges all applicable scopes into either token. fetchConfig().then(async (config) => { if (!config.logtoResource) return; const extractScopes = (token: string | undefined): string[] => { if (!token) return []; try { const payload = JSON.parse(atob(token.split('.')[1])); return ((payload.scope as string) ?? '').split(' ').filter(Boolean); } catch { return []; } }; try { const token = await (currentOrgId ? getAccessToken(config.logtoResource, currentOrgId) : getAccessToken(config.logtoResource) ).catch(() => undefined); setScopes(new Set(extractScopes(token))); } catch { setScopes(new Set()); } }); }, [me, currentOrgId]); if (isLoading) { return (
); } if (isError) { return null; } return <>{children}; }