sending images through messages works

This commit is contained in:
jackiettran
2025-12-18 19:37:16 -05:00
parent 996e815d57
commit 4b4584bc0f
6 changed files with 52 additions and 22 deletions

View File

@@ -0,0 +1,21 @@
"use strict";
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.changeColumn("Messages", "content", {
type: Sequelize.TEXT,
allowNull: true,
});
},
down: async (queryInterface, Sequelize) => {
// First update any null content to empty string before reverting
await queryInterface.sequelize.query(
`UPDATE "Messages" SET content = '' WHERE content IS NULL`
);
await queryInterface.changeColumn("Messages", "content", {
type: Sequelize.TEXT,
allowNull: false,
});
},
};

View File

@@ -25,7 +25,7 @@ const Message = sequelize.define('Message', {
}, },
content: { content: {
type: DataTypes.TEXT, type: DataTypes.TEXT,
allowNull: false allowNull: true
}, },
isRead: { isRead: {
type: DataTypes.BOOLEAN, type: DataTypes.BOOLEAN,
@@ -36,7 +36,15 @@ const Message = sequelize.define('Message', {
allowNull: true allowNull: true
} }
}, { }, {
timestamps: true timestamps: true,
validate: {
contentOrImage() {
const hasContent = this.content && this.content.trim().length > 0;
if (!hasContent && !this.imageFilename) {
throw new Error('Message must have content or an image');
}
}
}
}); });
module.exports = Message; module.exports = Message;

View File

@@ -316,7 +316,7 @@ router.post('/', authenticateToken, async (req, res, next) => {
error: error.message, error: error.message,
stack: error.stack, stack: error.stack,
senderId: req.user.id, senderId: req.user.id,
receiverId: req.body.receiverId receiverId: req.body?.receiverId
}); });
next(error); next(error);
} }

View File

@@ -6,7 +6,7 @@ import React, {
useCallback, useCallback,
} from "react"; } from "react";
import { messageAPI } from "../services/api"; import { messageAPI } from "../services/api";
import { getSignedUrl } from "../services/uploadService"; import { getSignedUrl, uploadFile } from "../services/uploadService";
import { User, Message } from "../types"; import { User, Message } from "../types";
import { useAuth } from "../contexts/AuthContext"; import { useAuth } from "../contexts/AuthContext";
import { useSocket } from "../contexts/SocketContext"; import { useSocket } from "../contexts/SocketContext";
@@ -374,15 +374,18 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
} }
try { try {
// Build FormData for message (with or without image) // Upload image to S3 first if present
const formData = new FormData(); let imageFilename: string | undefined;
formData.append("receiverId", recipient.id);
formData.append("content", messageContent || " "); // Send space if only image
if (imageToSend) { if (imageToSend) {
formData.append("image", imageToSend); const { key } = await uploadFile("message", imageToSend);
imageFilename = key;
} }
const response = await messageAPI.sendMessage(formData); const response = await messageAPI.sendMessage({
receiverId: recipient.id,
content: messageContent || "",
imageFilename,
});
// Add message to sender's chat immediately for instant feedback // Add message to sender's chat immediately for instant feedback
// Socket will handle updating the receiver's chat // Socket will handle updating the receiver's chat
@@ -559,7 +562,7 @@ const ChatWindow: React.FC<ChatWindowProps> = ({
/> />
</div> </div>
)} )}
{message.content.trim() && ( {message.content?.trim() && (
<p className="mb-1" style={{ fontSize: "0.95rem" }}> <p className="mb-1" style={{ fontSize: "0.95rem" }}>
{message.content} {message.content}
</p> </p>

View File

@@ -20,11 +20,10 @@ const MessageModal: React.FC<MessageModalProps> = ({ show, onClose, recipient, o
setSending(true); setSending(true);
try { try {
const formData = new FormData(); await messageAPI.sendMessage({
formData.append('receiverId', recipient.id); receiverId: recipient.id,
formData.append('content', content); content,
});
await messageAPI.sendMessage(formData);
setContent(''); setContent('');
onClose(); onClose();

View File

@@ -248,12 +248,11 @@ export const messageAPI = {
getSentMessages: () => api.get("/messages/sent"), getSentMessages: () => api.get("/messages/sent"),
getConversations: () => api.get("/messages/conversations"), getConversations: () => api.get("/messages/conversations"),
getMessage: (id: string) => api.get(`/messages/${id}`), getMessage: (id: string) => api.get(`/messages/${id}`),
sendMessage: (formData: FormData) => sendMessage: (data: {
api.post("/messages", formData, { receiverId: string;
headers: { content: string;
"Content-Type": "multipart/form-data", imageFilename?: string;
}, }) => api.post("/messages", data),
}),
markAsRead: (id: string) => api.put(`/messages/${id}/read`), markAsRead: (id: string) => api.put(`/messages/${id}/read`),
getUnreadCount: () => api.get("/messages/unread/count"), getUnreadCount: () => api.get("/messages/unread/count"),
}; };