import { keyBy } from 'es-toolkit'; import { useMemo } from 'react'; import axios, { endpoints, fetcher } from 'src/lib/axios'; import type { IChatConversation, IChatMessage, IChatParticipant } from 'src/types/chat'; import type { SWRConfiguration } from 'swr'; import useSWR, { mutate } from 'swr'; // ---------------------------------------------------------------------- const enableServer = false; const CHART_ENDPOINT = endpoints.chat; const swrOptions: SWRConfiguration = { revalidateIfStale: enableServer, revalidateOnFocus: enableServer, revalidateOnReconnect: enableServer, }; // ---------------------------------------------------------------------- type ContactsData = { contacts: IChatParticipant[]; }; export function useGetContacts() { const url = [CHART_ENDPOINT, { params: { endpoint: 'contacts' } }]; const { data, isLoading, error, isValidating } = useSWR(url, fetcher, swrOptions); const memoizedValue = useMemo( () => ({ contacts: data?.contacts || [], contactsLoading: isLoading, contactsError: error, contactsValidating: isValidating, contactsEmpty: !isLoading && !isValidating && !data?.contacts.length, }), [data?.contacts, error, isLoading, isValidating] ); return memoizedValue; } // ---------------------------------------------------------------------- type ConversationsData = { conversations: IChatConversation[]; }; export function useGetConversations() { const url = [CHART_ENDPOINT, { params: { endpoint: 'conversations' } }]; const { data, isLoading, error, isValidating } = useSWR( url, fetcher, swrOptions ); const memoizedValue = useMemo(() => { const byId = data?.conversations.length ? keyBy(data.conversations, (option) => option.id) : {}; const allIds = Object.keys(byId); return { conversations: { byId, allIds }, conversationsLoading: isLoading, conversationsError: error, conversationsValidating: isValidating, conversationsEmpty: !isLoading && !isValidating && !allIds.length, }; }, [data?.conversations, error, isLoading, isValidating]); return memoizedValue; } // ---------------------------------------------------------------------- type ConversationData = { conversation: IChatConversation; }; export function useGetConversation(conversationId: string) { const url = conversationId ? [CHART_ENDPOINT, { params: { conversationId, endpoint: 'conversation' } }] : ''; const { data, isLoading, error, isValidating } = useSWR( url, fetcher, swrOptions ); const memoizedValue = useMemo( () => ({ conversation: data?.conversation, conversationLoading: isLoading, conversationError: error, conversationValidating: isValidating, conversationEmpty: !isLoading && !isValidating && !data?.conversation, }), [data?.conversation, error, isLoading, isValidating] ); return memoizedValue; } // ---------------------------------------------------------------------- export async function sendMessage(conversationId: string, messageData: IChatMessage) { const conversationsUrl = [CHART_ENDPOINT, { params: { endpoint: 'conversations' } }]; const conversationUrl = [ CHART_ENDPOINT, { params: { conversationId, endpoint: 'conversation' } }, ]; /** * Work on server */ if (enableServer) { const data = { conversationId, messageData }; await axios.put(CHART_ENDPOINT, data); } /** * Work in local */ mutate( conversationUrl, (currentData) => { const currentConversation: IChatConversation = currentData.conversation; const conversation = { ...currentConversation, messages: [...currentConversation.messages, messageData], }; return { ...currentData, conversation }; }, false ); mutate( conversationsUrl, (currentData) => { const currentConversations: IChatConversation[] = currentData.conversations; const conversations: IChatConversation[] = currentConversations.map( (conversation: IChatConversation) => conversation.id === conversationId ? { ...conversation, messages: [...conversation.messages, messageData] } : conversation ); return { ...currentData, conversations }; }, false ); } // ---------------------------------------------------------------------- export async function createConversation(conversationData: IChatConversation) { const url = [CHART_ENDPOINT, { params: { endpoint: 'conversations' } }]; /** * Work on server */ const data = { conversationData }; const res = await axios.post(CHART_ENDPOINT, data); /** * Work in local */ mutate( url, (currentData) => { const currentConversations: IChatConversation[] = currentData.conversations; const conversations: IChatConversation[] = [...currentConversations, conversationData]; return { ...currentData, conversations }; }, false ); return res.data; } // ---------------------------------------------------------------------- export async function clickConversation(conversationId: string) { /** * Work on server */ if (enableServer) { await axios.get(CHART_ENDPOINT, { params: { conversationId, endpoint: 'mark-as-seen' } }); } /** * Work in local */ mutate( [CHART_ENDPOINT, { params: { endpoint: 'conversations' } }], (currentData) => { const currentConversations: IChatConversation[] = currentData.conversations; const conversations = currentConversations.map((conversation: IChatConversation) => conversation.id === conversationId ? { ...conversation, unreadCount: 0 } : conversation ); return { ...currentData, conversations }; }, false ); }