fixed images flickering and infinite loop on fetching previous messages

This commit is contained in:
slawk0
2024-12-04 13:52:35 +01:00
parent fb08f6e171
commit 722e1cfde9
3 changed files with 87 additions and 48 deletions

View File

@@ -0,0 +1,48 @@
import { useEffect, useState } from 'react';
import LoadingWheel from './LoadingWheel';
import FileBox from './FileBox';
// Cache to keep track of loaded images
const loadedImages = new Set<string>();
const AttachmentPreview = ({ url }: { url: string }) => {
const isImage = url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i);
const [isLoading, setIsLoading] = useState(!loadedImages.has(url));
useEffect(() => {
if (isImage && !loadedImages.has(url)) {
// Preload image
const img = new Image();
img.onload = () => {
loadedImages.add(url);
setIsLoading(false);
};
img.src = url;
}
}, [url, isImage]);
if (!isImage) {
return <FileBox url={url} />;
}
return (
<div className="relative min-h-64 w-full">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-800 bg-opacity-50 rounded">
<LoadingWheel />
</div>
)}
<a href={url} target="_blank">
<img
src={url}
alt="attachment"
className={`max-w-full max-h-64 object-contain rounded transition-opacity duration-200 ${
isLoading ? 'opacity-0' : 'opacity-100'
}`}
/>
</a>
</div>
);
};
export default AttachmentPreview;

View File

@@ -8,6 +8,7 @@ import FileBox from './FileBox.tsx';
import { ContactsProps } from '../../pages/Chat.tsx';
import { Trash2 } from 'lucide-react';
import { axiosClient } from '../../App.tsx';
import AttachmentPreview from './AttachmentPreview.tsx';
type MessagesAreaProps = {
messages: ChatMessages[];
@@ -19,6 +20,7 @@ type MessagesAreaProps = {
setContactsList: React.Dispatch<React.SetStateAction<ContactsProps[]>>;
fetchPreviousMessages: (contact: number | null) => Promise<void>;
errorMessage: string | null;
hasMoreMessages: boolean;
};
function MessagesArea({
@@ -30,6 +32,7 @@ function MessagesArea({
fetchPreviousMessages,
errorMessage,
setMessages,
hasMoreMessages,
}: MessagesAreaProps) {
const containerRef = useRef<HTMLDivElement>(null);
const { username }: { username: string } = useOutletContext();
@@ -164,33 +167,6 @@ function MessagesArea({
scrollToBottom();
}, []);
const AttachmentPreview = ({ url }: { url: string }) => {
const isImage = url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i);
const [isLoading, setIsLoading] = useState(true);
if (!isImage) {
return <FileBox url={url} />;
}
return (
<div className="relative min-h-64 w-full">
{isLoading && (
<div className="absolute inset-0 flex items-center justify-center bg-gray-800 bg-opacity-50 rounded">
<LoadingWheel />
</div>
)}
<img
src={url}
alt="attachment"
className={`max-w-full max-h-64 object-contain rounded transition-opacity duration-200 ${
isLoading ? 'opacity-0' : 'opacity-100'
}`}
onLoad={() => setIsLoading(false)}
/>
</div>
);
};
const messageList = messages.map((msg: ChatMessages) => (
<li
className={`whitespace-pre-wrap ml-2 rounded p-1 group ${

View File

@@ -38,7 +38,7 @@ function Chat() {
const [cursor, setCursor] = useState<number>(0);
const [messages, setMessages] = useState<ChatMessages[]>([]);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [hasMoreMessages, setHasMoreMessages] = useState<boolean>(true);
useEffect(() => {
const token = Cookies.get('token');
@@ -51,7 +51,6 @@ function Chat() {
const parsedContact = JSON.parse(storedContact);
if (parsedContact) {
initializeContact(parsedContact);
setIsLoading(true);
}
} catch (error) {
console.error('Failed to parse stored contact:', error);
@@ -80,7 +79,6 @@ function Chat() {
const fetchMessages = async (conversation_id: number) => {
console.log('Fetching messages for: ', conversation_id);
await getMessages(conversation_id)
.then((messages) => {
setCursor(() => {
@@ -90,32 +88,48 @@ function Chat() {
});
messages.messages.forEach(messageHandler);
setIsLoading(false);
})
.catch((error) => setErrorMessage(error.response.data.message));
};
const fetchPreviousMessages = async (contact: number | null) => {
console.log('Fetching messages for: ', contact, 'with cursor: ', cursor);
console.log(
'Fetching messages for: ',
contact,
'with cursor: ',
cursor,
'hasmoremessages: ',
hasMoreMessages,
);
await getMessages(contact, cursor, 50)
.then((messages) => {
messages.messages.forEach((msg) => {
setMessages((prevMessages) => {
if (!prevMessages.some((m) => m.message_id === msg.message_id)) {
return [msg, ...prevMessages];
}
return prevMessages;
});
});
if (!hasMoreMessages) {
return;
}
setCursor(() => {
return Math.min(
...messages.messages.map((message) => message.message_id),
);
try {
const messages = await getMessages(contact, cursor, 50);
console.log('fetchpreviousmessages: ', messages.messages.length);
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)) {
return [msg, ...prevMessages];
}
return prevMessages;
});
})
.catch((error) => setErrorMessage(error.response.data.message));
});
setCursor(() => {
return Math.min(
...messages.messages.map((message) => message.message_id),
);
});
} catch (e) {
setErrorMessage(e.response.data.message);
}
};
function messageHandler(msg: ChatMessages) {
setMessages((prevMessages) => {
@@ -180,6 +194,7 @@ function Chat() {
setContactsList={setContactsList}
fetchPreviousMessages={fetchPreviousMessages}
errorMessage={errorMessage}
hasMoreMessages={hasMoreMessages}
/>
</div>
<div className="flex-shrink-0 mb-2 mt-0">