i think i have fixed the bugs i did not think I would fix

This commit is contained in:
2024-10-24 15:03:28 -05:00
parent c0ebccf6b1
commit 0e46c630a6
5 changed files with 208 additions and 90 deletions

View File

@ -1,4 +1,5 @@
import React, { useCallback, useEffect, useReducer, useState } from 'react';
import React, { useCallback, useEffect, useReducer, useState, useRef } from 'react';
import { io } from 'socket.io-client';
import { ThemedText, ThemedView } from '@/components/theme/Theme';
import { Alert, Linking, Platform, StyleSheet, ActivityIndicator } from 'react-native';
import { MaterialIcons } from '@expo/vector-icons';
@ -27,14 +28,21 @@ import {getMessages, sendMessage} from '@/constants/APIs';
import { getUser, getPartner } from '@/components/services/SecureStore';
import { sendPushNotification } from '@/components/services/notifications/PushNotificationManager';
// Reducer function for managing state
const reducer = (state: GCState, action: GCStateAction) => {
switch (action.type) {
case ActionKind.SEND_MESSAGE: {
return { ...state, messages: action.payload };
return {
...state,
messages: action.payload
};
}
case ActionKind.LOAD_EARLIER_MESSAGES: {
return { ...state, loadEarlier: true,
isLoadingEarlier: false, messages: action.payload
return {
...state,
loadEarlier: true,
isLoadingEarlier: false,
messages: action.payload
};
}
case ActionKind.LOAD_EARLIER_START: {
@ -50,14 +58,14 @@ const reducer = (state: GCState, action: GCStateAction) => {
const MessagesScreen = () => {
const [user, setUser] = useState<User | null>(null);
const [partner, setPartner] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [state, dispatch] = useReducer(reducer, {
messages: [],
step: 0,
loadEarlier: true,
isLoadingEarlier: false,
isTyping: false,
});
// Get user and partner data from SecureStore
const msgUser: GCUser = {
_id: user?.id ?? 0,
name: user?.fullName ?? 'You',
@ -71,6 +79,7 @@ const MessagesScreen = () => {
`${process.env.EXPO_PUBLIC_API_URL}/images/default-profile.png`,
};
// Initialize users & (trying to) fetch & display initial messages
useEffect(() => {
const initialize = async () => {
try{
@ -79,31 +88,70 @@ const MessagesScreen = () => {
if (userData && partnerData) {
setUser(userData);
setPartner(partnerData);
await fetchInitialMessages(userData.id);
} else
throw new Error('User or partner not found');
} catch (error) {
console.error('Error initializing users:', error);
Alert.alert('Error', 'Failed to initialize users. Please try again.');
} finally {
setLoading(false);
dispatch({ type: ActionKind.LOAD_EARLIER_MESSAGES, payload: [] });
}
};
initialize();
}, []);
const fetchInitialMessages = async (userId: number, limit: number = 20, offset: number = 0) => {
try {
const initialMessages = await getMessages(userId, limit, offset);
if (initialMessages) {
const formattedMessages = formatMessages(initialMessages);
dispatch({ type: ActionKind.SEND_MESSAGE, payload: formattedMessages });
}
} catch (error) {
console.error('Error fetching initial messages:', error);
}
};
useEffect(() => {
if (!user || !partner) return;
const socket = io(process.env.EXPO_PUBLIC_WEBSOCKET_URL as string, {
transports: ['websocket'],
});
socket.on('connect', () => {
//console.log('Connected to WebSocket server');
socket.emit('join', user.id);
});
socket.on('connect_error', (error) => {
console.error('Error connecting to WebSocket server:', error);
});
socket.on('message', async (newMessage) => {
console.log('New message received:', newMessage);
const formattedMessage = formatMessages([newMessage]);
dispatch({
type: ActionKind.SEND_MESSAGE,
payload: GiftedChat.append(state.messages, formattedMessage),
});
if (user && partner) {
dispatch({ type: ActionKind.LOAD_EARLIER_START });
const initialMessages = await getMessages(user.id, 20, 0);
console.log('initial messages: ', initialMessages);
if (initialMessages) {
const formattedMessages = formatMessages(initialMessages);
console.log('formatted messages: ', formattedMessages);
dispatch({
type: ActionKind.LOAD_EARLIER_MESSAGES,
payload: formattedMessages,
});
}
} else console.log('user or partner not initialized');
});
return () => {
socket.disconnect();
};
}, [user, partner]);
useEffect(() => {
const fetchMessages = async () => {
if (user && partner) {
dispatch({ type: ActionKind.LOAD_EARLIER_START });
const initialMessages = await getMessages(user.id, 20, 0);
if (initialMessages) {
const formattedMessages = formatMessages(initialMessages);
dispatch({ type: ActionKind.LOAD_EARLIER_MESSAGES, payload: formattedMessages });
}
}
};
fetchMessages();
}, [user, partner]);
// Format messages for GiftedChat
const formatMessages = (dbMessages: Message[]): IMessage[] => {
if (!user || !partner) return [];
return dbMessages.map((msg) => ({
@ -111,88 +159,86 @@ const MessagesScreen = () => {
text: msg.text,
createdAt: new Date(msg.createdAt),
user: msg.senderId === user.id ? msgUser : msgPartner,
})) as IMessage[];
};
const onSend = useCallback(async (messages: any[]) => {
if (!user || !partner) return;
// Prepare the message to be sent
const createdAt = new Date();
const tempId = Math.round(Math.random() * -1000000); // Temporary ID
const messageToSend: Message = {
id: tempId,
senderId: user.id,
receiverId: partner?.id ?? 0,
text: messages[0].text,
createdAt,
isRead: false,
hasLocation: false,
hasMedia: false,
hasQuickReply: false,
})) as IMessage[];
};
const notificationMessage: NotificationMessage = {
sound: 'default',
title: 'New message from ' + user.fullName,
body: messageToSend.text,
data: {
message: messageToSend,
},
};
//sendPushNotification(partner.pushToken, notificationMessage);
sendPushNotification(user.pushToken, notificationMessage);
// Add the message with a tempId immediately to the state
const tempFormattedMessages = formatMessages([messageToSend]);
dispatch({
type: ActionKind.SEND_MESSAGE,
payload: GiftedChat.append(state.messages, tempFormattedMessages),
});
/* -------- Send message function -------- */
const onSend = useCallback(async (messages: any[]) => {
if (!user || !partner) return;
try {
// Send the message to the server
const sentMessage = await sendMessage(messageToSend);
// Prepare the message to be sent
const createdAt = new Date();
const tempId = Math.round(Math.random() * -1000000); // Temporary ID
// Fetch the latest messages from the server to ensure consistency
const updatedMessages = await getMessages(user?.id ?? 0);
if (updatedMessages) {
const formattedMessages = formatMessages(updatedMessages);
dispatch({ type: ActionKind.SEND_MESSAGE, payload: formattedMessages });
const messageToSend: Message = {
id: tempId,
senderId: user.id,
receiverId: partner?.id ?? 0,
text: messages[0].text,
createdAt,
isRead: false,
hasLocation: false,
hasMedia: false,
hasQuickReply: false,
};
const notificationMessage: NotificationMessage = {
sound: 'default',
title: 'New message from ' + user.fullName,
body: messageToSend.text,
data: {
message: messageToSend,
},
};
//sendPushNotification(partner.pushToken, notificationMessage);
sendPushNotification(user.pushToken, notificationMessage);
// Add the message with a tempId immediately to the state
const tempFormattedMessages = formatMessages([messageToSend]);
const updatedMessages = GiftedChat.append(state.messages, tempFormattedMessages);
dispatch({
type: ActionKind.SEND_MESSAGE,
payload: updatedMessages,
});
try {
// Send the message to the server
const sentMessage = await sendMessage(messageToSend);
// Fetch the latest messages from the server to ensure consistency
const updatedMessages = await getMessages(user?.id ?? 0);
if (updatedMessages) {
const formattedMessages = formatMessages(updatedMessages);
dispatch({ type: ActionKind.SEND_MESSAGE, payload: formattedMessages });
}
} catch (error) {
console.error('Error sending message:', error);
// In case of an error, remove the temporary message from the state
const updatedMessages = state.messages.filter((msg) => msg._id !== tempId);
dispatch({ type: ActionKind.SEND_MESSAGE, payload: updatedMessages });
Alert.alert('Error', 'Failed to send message. Please try again.');
}
} catch (error) {
console.error('Error sending message:', error);
// In case of an error, remove the temporary message from the state
const updatedMessages = state.messages.filter((msg) => msg._id !== tempId);
dispatch({ type: ActionKind.SEND_MESSAGE, payload: updatedMessages });
Alert.alert('Error', 'Failed to send message. Please try again.');
}
}, [user, partner, state.messages]);
}, [user, partner, state.messages]);
const onLoadEarlier = useCallback(async () => {
if (!user) return;
if (!user) {
console.log('User not found');
return;
}
// Set loading state
dispatch({ type: ActionKind.LOAD_EARLIER_START });
// Fetch the current size of messages already in chat to calculate the new offset
const offset = state.messages.length;
try {
const earlierMessages = await getMessages(user.id, 20, offset);
if (earlierMessages) {
const formattedMessages = formatMessages(earlierMessages);
// Prepend older messages
dispatch({
type: ActionKind.LOAD_EARLIER_MESSAGES,
payload: GiftedChat.prepend(state.messages, formattedMessages),
});
const updatedMessages = GiftedChat.prepend(state.messages, formattedMessages);
dispatch({ type: ActionKind.LOAD_EARLIER_MESSAGES, payload: updatedMessages });
}
} catch (error) {
console.error('Error loading earlier messages:', error);
dispatch({ type: ActionKind.LOAD_EARLIER_MESSAGES, payload: [] });
}
}, [user, state.messages]);
@ -307,10 +353,6 @@ const onSend = useCallback(async (messages: any[]) => {
);
}, []);
if (loading) return (
<ActivityIndicator size='large' color='#0000ff'/>
);
return (
<SafeAreaView style={styles.fill}>
<ThemedView style={styles.fill}>