Files
relay/client/src/context/chat/ChatProvider.tsx

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