181 lines
5.1 KiB
TypeScript
181 lines
5.1 KiB
TypeScript
import { ChatContext } from '@/context/chat/ChatContext.tsx';
|
|
import { ReactNode, useState } from 'react';
|
|
import { ChatMessagesProps, ContactsProps, MeProps } from '@/types/types.ts';
|
|
import { joinRoom } from '@/socket/socket.ts';
|
|
import { getMessages, setContactStatus } from '@/api/contactsApi.tsx';
|
|
import axios from 'axios';
|
|
|
|
export const ChatProvider = ({ children }: { children: ReactNode }) => {
|
|
const [contactsList, setContactsList] = useState<ContactsProps[]>([]);
|
|
const [currentContact, setCurrentContact] = useState<ContactsProps | null>(
|
|
null,
|
|
);
|
|
const [cursor, setCursor] = useState<number>(0);
|
|
const [messages, setMessages] = useState<ChatMessagesProps[]>([]);
|
|
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
const [hasMoreMessages, setHasMoreMessages] = useState<boolean>(true);
|
|
const [me, setMe] = useState<MeProps>({
|
|
isGroupAdmin: false,
|
|
isGroupOwner: false,
|
|
});
|
|
const [groupOwner, setGroupOwner] = useState<string | undefined>();
|
|
|
|
async function initializeContact(newContact: ContactsProps) {
|
|
setMessages([]); // Clear messages from previous contact
|
|
localStorage.setItem('contact', JSON.stringify(newContact)); // Set current contact in localstorage
|
|
setCurrentContact({ ...newContact, read: true });
|
|
console.log('Initialized contact: ', newContact);
|
|
try {
|
|
const joinResult = await joinRoom(newContact.conversation_id);
|
|
if (!joinResult.success) {
|
|
setErrorMessage(joinResult.message);
|
|
return false;
|
|
}
|
|
try {
|
|
await fetchMessages(newContact.conversation_id);
|
|
} catch (e) {
|
|
console.error('Failed to fetch messages: ', e);
|
|
return false;
|
|
}
|
|
setContactsList((prevContacts) =>
|
|
prevContacts.map((c) =>
|
|
c.username === newContact.username ? { ...c, read: true } : c,
|
|
),
|
|
);
|
|
console.log('Current contact is now: ', newContact);
|
|
return true;
|
|
} catch (e) {
|
|
console.error('Failed to initialize contact:', e);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const fetchMessages = async (conversation_id: string) => {
|
|
console.log('Fetching messages for: ', conversation_id);
|
|
try {
|
|
const messages = await getMessages(conversation_id);
|
|
if (messages.messages.length < 50) {
|
|
setHasMoreMessages(false);
|
|
setErrorMessage('No more messages found');
|
|
}
|
|
|
|
setCursor(() => {
|
|
return Math.min(
|
|
...messages.messages.map((message) => message.message_id),
|
|
);
|
|
});
|
|
|
|
messages.messages.forEach(messageHandler);
|
|
} catch (e) {
|
|
if (axios.isAxiosError(e)) {
|
|
setErrorMessage(e.message);
|
|
}
|
|
}
|
|
};
|
|
|
|
function messageHandler(msg: ChatMessagesProps) {
|
|
setMessages((prevMessages) => {
|
|
// Check if the message already exists in the state
|
|
if (!prevMessages.some((m) => m.message_id === msg.message_id)) {
|
|
// Convert sent_at to Date object before adding to state
|
|
const messageWithDate = {
|
|
...msg,
|
|
sent_at: new Date(msg.sent_at),
|
|
};
|
|
return [...prevMessages, messageWithDate];
|
|
}
|
|
return prevMessages;
|
|
});
|
|
}
|
|
|
|
function updateContactStatus(conversation_id: string, read: boolean) {
|
|
console.log('Update contact status: ', conversation_id);
|
|
|
|
setContactsList((prevContacts) =>
|
|
prevContacts.map((contact) => {
|
|
if (contact.conversation_id === conversation_id) {
|
|
setContactStatus(conversation_id, read);
|
|
|
|
return { ...contact, read: read };
|
|
} else {
|
|
return contact;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
|
|
const fetchPreviousMessages = async (contact: string | null) => {
|
|
if (!hasMoreMessages) {
|
|
return;
|
|
}
|
|
|
|
console.log(
|
|
'Fetching messages for: ',
|
|
contact,
|
|
'with cursor: ',
|
|
cursor,
|
|
'hasmoremessages: ',
|
|
hasMoreMessages,
|
|
);
|
|
|
|
try {
|
|
const messages = await getMessages(contact, cursor, 50);
|
|
if (messages.messages.length < 50) {
|
|
setHasMoreMessages(false);
|
|
setErrorMessage('No more messages found');
|
|
}
|
|
messages.messages.forEach((msg) => {
|
|
setMessages((prevMessages) => {
|
|
if (!prevMessages.some((m) => m.message_id === msg.message_id)) {
|
|
const messageWithDate = {
|
|
...msg,
|
|
sent_at: new Date(msg.sent_at),
|
|
};
|
|
|
|
return [messageWithDate, ...prevMessages];
|
|
}
|
|
return prevMessages;
|
|
});
|
|
});
|
|
|
|
setCursor(() => {
|
|
return Math.min(
|
|
...messages.messages.map((message) => message.message_id),
|
|
);
|
|
});
|
|
} catch (e) {
|
|
if (axios.isAxiosError(e)) {
|
|
setErrorMessage(e.message);
|
|
}
|
|
}
|
|
};
|
|
|
|
const value = {
|
|
contactsList,
|
|
currentContact,
|
|
cursor,
|
|
messages,
|
|
errorMessage,
|
|
hasMoreMessages,
|
|
me,
|
|
groupOwner,
|
|
|
|
setContactsList,
|
|
setCurrentContact,
|
|
setCursor,
|
|
setMessages,
|
|
setErrorMessage,
|
|
setHasMoreMessages,
|
|
setMe,
|
|
setGroupOwner,
|
|
|
|
initializeContact,
|
|
fetchMessages,
|
|
messageHandler,
|
|
updateContactStatus,
|
|
fetchPreviousMessages,
|
|
};
|
|
|
|
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
|
|
};
|