import { useCallback, useEffect, useState } from 'react'; import type { Conversation } from '@altricade/core'; import { userChannel } from '@altricade/core'; import { listConversations, createDirect, createGroup } from '@altricade/core/api'; import { apiConfig } from '../../shared/api'; import { useRealtime } from '../realtime'; export interface UseConversations { conversations: Conversation[]; loading: boolean; startDirect: (username: string) => Promise; createGroupChat: (title: string, members: string[]) => Promise; } const isConversationNew = ( data: unknown, ): data is { type: 'conversation.new'; conversation: Conversation } => { if (typeof data !== 'object' || data === null) { return false; } return 'type' in data && data.type === 'conversation.new' && 'conversation' in data; }; const upsert = (list: Conversation[], conversation: Conversation): Conversation[] => { const rest = list.filter((item) => item.id !== conversation.id); return [conversation, ...rest]; }; export const useConversations = (userId: string): UseConversations => { const { subscribe } = useRealtime(); const [conversations, setConversations] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { let cancelled = false; const load = async (): Promise => { try { const list = await listConversations(apiConfig); if (!cancelled) { setConversations(list); } } finally { if (!cancelled) { setLoading(false); } } }; void load(); return () => { cancelled = true; }; }, []); // New conversations (a DM someone started with me, or a group I was added to) // arrive on my personal channel. useEffect(() => { return subscribe(userChannel(userId), (event) => { if (isConversationNew(event.data)) { const { conversation } = event.data; setConversations((prev) => upsert(prev, conversation)); } }); }, [subscribe, userId]); const startDirect = useCallback(async (username: string): Promise => { const conversation = await createDirect(apiConfig, { username }); setConversations((prev) => upsert(prev, conversation)); return conversation; }, []); const createGroupChat = useCallback( async (title: string, members: string[]): Promise => { const conversation = await createGroup(apiConfig, { title, members }); setConversations((prev) => upsert(prev, conversation)); return conversation; }, [], ); return { conversations, loading, startDirect, createGroupChat }; };