ultisuite-client/lib/drive/use-collab-presence.ts
2026-06-09 17:06:20 +02:00

64 lines
1.7 KiB
TypeScript

"use client"
import { useEffect, useState } from "react"
import type { HocuspocusProvider } from "@hocuspocus/provider"
import { colorForGuestId } from "@/lib/drive/guest-editor-identity"
export type CollabPresenceUser = {
clientId: number
name: string
color: string
isLocal: boolean
}
type AwarenessUser = {
name?: string
color?: string
}
export function useCollabPresence(
provider: HocuspocusProvider | null,
localUser: { name: string; color: string }
): CollabPresenceUser[] {
const [users, setUsers] = useState<CollabPresenceUser[]>([
{ clientId: -1, name: localUser.name, color: localUser.color, isLocal: true },
])
useEffect(() => {
if (!provider) {
setUsers([
{ clientId: -1, name: localUser.name, color: localUser.color, isLocal: true },
])
return
}
const awareness = provider.awareness
if (!awareness) return
const sync = () => {
const list: CollabPresenceUser[] = []
awareness.getStates().forEach((state, clientId) => {
const user = state.user as AwarenessUser | undefined
const name = user?.name?.trim()
if (!name) return
list.push({
clientId,
name,
color: user?.color && user.color.length > 0 ? user.color : colorForGuestId(String(clientId)),
isLocal: clientId === awareness.clientID,
})
})
list.sort((a, b) => Number(b.isLocal) - Number(a.isLocal) || a.name.localeCompare(b.name, "fr"))
setUsers(list.length > 0 ? list : [{ clientId: -1, name: localUser.name, color: localUser.color, isLocal: true }])
}
awareness.on("change", sync)
sync()
return () => {
awareness.off("change", sync)
}
}, [provider, localUser.name, localUser.color])
return users
}