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(); 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); } // Read scopes from the access token JWT payload fetchConfig().then((config) => { if (!config.logtoResource) return; getAccessToken(config.logtoResource).then((token) => { if (!token) return; try { const payload = JSON.parse(atob(token.split('.')[1])); const scopeStr = (payload.scope as string) ?? ''; setScopes(new Set(scopeStr.split(' ').filter(Boolean))); } catch { setScopes(new Set()); } }).catch(() => setScopes(new Set())); }); }, [me]); if (isLoading) { return (