219 lines
5.7 KiB
TypeScript
219 lines
5.7 KiB
TypeScript
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<ContactsData>(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<ConversationsData>(
|
|
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<ConversationData>(
|
|
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
|
|
);
|
|
}
|