File
Blob: src/client/lib/collab-identity.ts
| 1 | import { useMemo } from "react"; |
| 2 | import { useAuthStore } from "@/client/stores/auth-store"; |
| 3 | import { useWorkspaceMembers } from "@/client/stores/workspace-replica"; |
| 4 | import { useActivePageState } from "@/client/components/active-page/use-active-page"; |
| 5 | import { friendlyName } from "@/client/lib/friendly-name"; |
| 6 | import type { ResolveIdentity } from "@/client/lib/presence-identity"; |
| 7 | |
| 8 | export interface CollabIdentity { |
| 9 | userId: string | null; |
| 10 | resolveIdentity: ResolveIdentity; |
| 11 | } |
| 12 | |
| 13 | /** |
| 14 | * Derives collaboration identity for the active page. Returns the signed-in |
| 15 | * user's id (null when anonymous / share-token) and a memoized `resolveIdentity` |
| 16 | * that maps awareness userId+clientId to a display identity. Workspace members |
| 17 | * are the source of truth for names and avatars; share surfaces (where the |
| 18 | * viewer isn't a workspace member) fall back to a generated friendlyName. |
| 19 | * |
| 20 | * Memoization is keyed on the members array so `CanvasSurface`'s depsRef |
| 21 | * rebuild-avoidance stays intact — `resolveIdentity` only changes when members |
| 22 | * add or remove. |
| 23 | */ |
| 24 | export function useCollabIdentity(): CollabIdentity { |
| 25 | const userId = useAuthStore((s) => s.user?.id ?? null); |
| 26 | const state = useActivePageState(); |
| 27 | const workspaceId = state.kind === "ready" ? state.snapshot.workspaceId : null; |
| 28 | const members = useWorkspaceMembers(workspaceId); |
| 29 | |
| 30 | const resolveIdentity = useMemo<ResolveIdentity>(() => { |
| 31 | const byId = new Map(members.map((m) => [m.user_id, m.user])); |
| 32 | return (lookupUserId, clientId) => { |
| 33 | const real = lookupUserId ? byId.get(lookupUserId) : undefined; |
| 34 | if (real) return { name: real.name, avatar_url: real.avatar_url }; |
| 35 | return { name: friendlyName(lookupUserId ?? String(clientId)), avatar_url: null }; |
| 36 | }; |
| 37 | }, [members]); |
| 38 | |
| 39 | return { userId, resolveIdentity }; |
| 40 | } |