/** * The list of staff colleagues for the chat drawer, merged with live presence so * each row shows online / away / offline. Backed by the slim /api/chat/directory * endpoint (only chat-eligible staff, only id/name/email) — fast enough that the * drawer fills in quickly instead of sitting on "Keine Kollegen" for seconds. * Excludes the current user. Result is cached (5 min) in shared state so toggling * the drawer doesn't refetch every time; presence is merged live on top. */ const CACHE_MS = 5 * 60 * 1000 export const useStaffDirectory = () => { const presence = useChatPresence() const unread = useChatUnread() const users = useState('chatStaffUsers', () => []) const loading = useState('chatStaffLoading', () => false) const loadedAt = useState('chatStaffLoadedAt', () => 0) const userId = useCookie('logship_user_id') const load = async (force = false) => { if (loading.value) return if (!force && users.value.length && (Date.now() - loadedAt.value) < CACHE_MS) return loading.value = true try { const me = Number(userId.value || 0) const res: any = await $fetch('/api/chat/directory', { headers: useRequestHeaders(['cookie']) }) users.value = (res?.records || []) .filter((u: any) => Number(u.id) !== me) .map((u: any) => ({ id: Number(u.id), name: u.name || u.Name || ('User ' + u.id), email: u.email || u.EMail || '' })) loadedAt.value = Date.now() } catch (err) { console.error('[useStaffDirectory] load failed:', err) } finally { loading.value = false } } const order: Record = { online: 0, away: 1, offline: 2 } const list = computed(() => users.value .map((u: any) => ({ ...u, status: presence.value[u.id] || 'offline', unread: Number(unread.value[u.id] || 0) })) // Unread conversations float to the top, then online → away → offline, then name. .sort((a: any, b: any) => (Number(b.unread > 0) - Number(a.unread > 0)) || (order[a.status] - order[b.status]) || a.name.localeCompare(b.name))) return { load, list, users, loading } }