refinement phase 2

This commit is contained in:
hamid
2026-07-13 01:14:35 +03:30
parent 0b45ec51f4
commit 1ce36f9414
22 changed files with 519 additions and 27 deletions
@@ -0,0 +1,28 @@
import { useMe } from './useMe';
import { toAppRoles } from '../routing';
import type { Me } from '../types';
import type { AppRole } from '@/constants';
/**
* The resolved-vs-pending role state for a private route. The core refinement-phase-2 fix: a shell must
* distinguish **"/me hasn't resolved yet"** from **"the user has no nurse/admin role"** — conflating the
* two is what silently showed a nurse the customer app (a fresh `/me` in-flight fell through the
* `DEFAULT_ROLE = customer` fallback). This exposes that distinction so `RoleGuard` can render a neutral
* loading state while pending, an explicit error state when `/me` failed, and only route on a resolved
* role set.
*
* `error` fires only when `/me` has no data at all; a background refetch that fails while we still hold a
* cached identity keeps serving `ready` (don't downgrade a known nurse on a transient blip).
*/
export type RoleHydration =
| { status: 'loading' }
| { status: 'error'; retry: () => void; isRetrying: boolean }
| { status: 'ready'; me: Me; appRoles: AppRole[] };
export function useRoleHydration(): RoleHydration {
const { data: me, isError, isFetching, refetch } = useMe();
if (me) return { status: 'ready', me, appRoles: toAppRoles(me.roles) };
if (isError) return { status: 'error', retry: () => void refetch(), isRetrying: isFetching };
return { status: 'loading' };
}