sending images through messages works
This commit is contained in:
@@ -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,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -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;
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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"),
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user