diff --git a/client/Dockerfile b/client/Dockerfile index 6a60006..6097cae 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -15,11 +15,13 @@ FROM nginx:alpine # Remove the default Nginx configuration file RUN rm /etc/nginx/conf.d/default.conf +RUN mkdir -p /app/attachments && chown -R node:node /app/attachments + # Copy the built files from the builder stage to the Nginx image COPY --from=builder /app/client/dist /usr/share/nginx/html # Expose port 80 EXPOSE 80 - +USER node # Start Nginx in the foreground CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/client/src/components/chat/chatArea/AnimatedMessage.tsx b/client/src/components/chat/chatArea/AnimatedMessage.tsx index 10697dd..8a59f93 100644 --- a/client/src/components/chat/chatArea/AnimatedMessage.tsx +++ b/client/src/components/chat/chatArea/AnimatedMessage.tsx @@ -28,7 +28,7 @@ const AnimatedMessage = ({ onDelete, message }: AnimatedMessageProps) => { ${isRemoving ? 'transition-all duration-300 opacity-0 -translate-x-full' : 'opacity-100'}`} >
-
+
{ {message.sender}: {message.message} {message.attachment_urls && ( -
- {message.attachment_urls.length > 0 +
+ {message.attachment_urls?.length > 0 ? message.attachment_urls.map((url, index) => ( { const isImage = url.match(/\.(jpg|jpeg|png|gif|bmp|webp)$/i); const isVideo = url.match(/\.(mp4|webm|ogg|mov)$/i); const [isLoading, setIsLoading] = useState(!loadedMedia.has(url)); - useEffect(() => { if (isImage && !loadedMedia.has(url)) { - // Preload image const img = new Image(); img.onload = () => { loadedMedia.add(url); @@ -20,7 +17,6 @@ const AttachmentPreview = ({ url }: { url: string }) => { }; img.src = url; } else if (isVideo && !loadedMedia.has(url)) { - // Preload video metadata const video = document.createElement('video'); video.onloadedmetadata = () => { loadedMedia.add(url); @@ -28,6 +24,7 @@ const AttachmentPreview = ({ url }: { url: string }) => { }; video.src = url; } + // setIsLoading(true); }, [url, isImage, isVideo]); if (!isImage && !isVideo) { @@ -36,15 +33,15 @@ const AttachmentPreview = ({ url }: { url: string }) => { if (isVideo) { return ( -
+
{isLoading && ( -
+
)}
diff --git a/docker-compose.yml b/docker-compose.yml index 91f05cc..27dcc06 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,7 +14,7 @@ services: ports: - "3000" volumes: - - attachments:/app/client/server/attachments + - attachments:/app/attachments depends_on: db: condition: service_healthy @@ -59,4 +59,5 @@ networks: driver: bridge volumes: - postgres-data: \ No newline at end of file + postgres-data: + attachments: \ No newline at end of file diff --git a/server/db/db.js b/server/db/db.js index d97821a..82fe499 100644 --- a/server/db/db.js +++ b/server/db/db.js @@ -568,7 +568,29 @@ async function insertContact(userUsername, receiverUsername, read) { ]); const contact = contactResult.rows[0]; - // 6. Return formatted result with contact's user_id + // 6. Retrieve the last message, last active time, and last message sender + const lastMessageQuery = ` + SELECT DISTINCT ON (m.conversation_id) + m.content AS last_message, + m.sent_at AS last_message_time, + a.username AS last_message_sender + FROM Messages m + JOIN Accounts a ON m.user_id = a.user_id + WHERE m.conversation_id = $1 + ORDER BY m.conversation_id, m.sent_at DESC + `; + const lastMessageResult = await client.query(lastMessageQuery, [ + conversation_id, + ]); + let lastMessage, lastMessageTime, lastMessageSender; + + if (lastMessageResult.rows.length > 0) { + lastMessage = lastMessageResult.rows[0].last_message; + lastMessageTime = lastMessageResult.rows[0].last_message_time; + lastMessageSender = lastMessageResult.rows[0].last_message_sender; + } + + // 7. Return formatted result with contact's user_id, last message, last active time, and last message sender return { id: contact.contact_id, user_id: contact_id, // Now using the contact's user_id instead of the initiator's @@ -577,6 +599,9 @@ async function insertContact(userUsername, receiverUsername, read) { conversation_id: contact.conversation_id, type: "direct", read: contact.read, + last_message: lastMessage, + last_message_time: lastMessageTime, + last_message_sender: lastMessageSender, }; } catch (error) { console.error("Failed to insert contact:", error);