Files
HKSingleParty/03_source/frontend/src/actions/chat.ts
louiscklaw 253c2f2487 update,
2025-06-15 04:23:06 +08:00

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
);
}