64 lines
1.7 KiB
TypeScript
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
|
|
}
|