uploading attachments is working and images are displayed

This commit is contained in:
slawk0
2024-11-21 19:15:24 +01:00
parent 7a3c17eff3
commit 1c37c11035
7 changed files with 78 additions and 31 deletions

View File

@@ -54,6 +54,7 @@ export async function getMessages(
`/api/chat/messages/${contact}?limit=${limit}&cursor=${cursor}`,
);
console.log('Get messages response: ', response.data);
return response.data;
} catch (e) {
console.error('Failed to get messages: ', e);

View File

@@ -11,7 +11,7 @@ const nanoid = customAlphabet('1234567890', 5);
type Input = {
message: string;
file: FileList | null;
attachment: FileList | null;
};
type MessageFormProps = {
@@ -24,6 +24,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
const { username }: { username: string } = useOutletContext();
const [file, setFile] = useState<File | null>(null);
const [isUploading, setIsUploading] = useState(false);
const fileInputRef = useRef<HTMLInputElement | null>(null);
const { register, handleSubmit, reset, watch, setValue } = useForm<Input>({
mode: 'onChange',
@@ -66,7 +67,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
},
);
setIsUploading(false);
return response.data.attachmentUrl;
return response.data;
} catch (e) {
setIsUploading(false);
console.error('Failed to upload attachment: ', e);
@@ -83,11 +84,12 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
return;
}
let attachmentUrl: string | null = null;
let attachmentUrl = null;
if (file) {
attachmentUrl = await uploadFile(file);
if (!attachmentUrl) {
const response = await uploadFile(file);
if (response?.attachment_url) {
attachmentUrl = response.attachment_url;
} else {
console.error('Failed to upload attachment');
return;
}
@@ -102,7 +104,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
message_id: 0, // Set to 0 because of key={msg.message_id || msg.tempId} in messages list
pending: true,
tempId: tempId,
attachment: attachmentUrl || null,
attachment_url: attachmentUrl || null,
};
setMessages((prevMessages) => [...prevMessages, tempMessage]); // Display as gray
@@ -113,9 +115,14 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
message: data.message.trim(),
recipient: contact,
tempId: tempId,
attachmentUrl: attachmentUrl || undefined,
attachment_url: attachmentUrl,
},
(response: { status: string; message_id: number; tempId: string }) => {
(response: {
status: string;
message_id: number;
tempId: number;
message: string;
}) => {
if (response.status === 'ok') {
setMessages((prevMessages) =>
prevMessages.map((msg) =>
@@ -126,10 +133,12 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
);
reset({ message: '' });
setValue('file', null);
setValue('attachment', null);
setFile(null);
}
console.log(response.status, response.tempId);
console.log(
`status: ${response.status}, tempId: ${response.tempId}, message: ${response.message}`,
);
},
);
@@ -137,7 +146,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
message: data.message.trim(),
recipient: contact,
tempId: tempId,
attachmentUrl: attachmentUrl,
attachment_url: attachmentUrl,
});
};
@@ -152,7 +161,7 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files.length > 0) {
setFile(e.target.files[0]);
setValue('file', e.target.files); // Update form state with file
setValue('attachment', e.target.files); // Update form state with file
}
};
@@ -200,13 +209,14 @@ const MessageForm = ({ contact, setMessages }: MessageFormProps) => {
</span>
</div>
</div>
<div className="flex flex-col gap-2">
<div className="flex gap-2">
<input
name="attachment"
type="file"
accept="*/*"
onChange={handleFileChange}
disabled={isUploading}
ref={fileInputRef}
/>
{isUploading && (
<span className="text-gray-500 text-sm">Uploading...</span>

View File

@@ -125,7 +125,19 @@ function MessagesArea({
}`}
key={msg.message_id || msg.tempId}
>
{msg.tempId} {msg.message_id} {msg.sender}: {msg.message}
{msg.sender}: {msg.message}
{msg.attachment_url ? (
<div className="mt-2">
<a href={msg.attachment_url}>
{' '}
<img
src={msg.attachment_url}
alt="attachment"
className="max-w-full max-h-80 object-contain rounded"
/>
</a>
</div>
) : null}
</li>
));

View File

@@ -16,7 +16,7 @@ export type ChatMessages = {
message_id: number;
tempId: string;
pending: boolean;
attachment: string | null;
attachment_url: string | null;
};
type ContactsProps = {
usernamecontact: string;

View File

@@ -45,10 +45,10 @@ async function createTables() {
CREATE TABLE IF NOT EXISTS messages (
sender VARCHAR(128) NOT NULL,
recipient VARCHAR(128) NOT NULL,
message VARCHAR(10000) NOT NULL,
message TEXT NOT NULL,
timestamp TIMESTAMPTZ DEFAULT NOW(),
message_id SERIAL PRIMARY KEY,
attachment VARCHAR(1000),
attachment_url TEXT,
UNIQUE (sender, recipient, message_id)
);
CREATE INDEX IF NOT EXISTS idx_messages_conversation
@@ -99,14 +99,19 @@ async function getUserId(username) {
console.error("Failed to get user id", e);
}
}
async function insertMessage(sender, recipient, message) {
async function insertMessage(sender, recipient, message, attachmentUrl) {
const query = `
INSERT INTO messages (sender, recipient, message)
VALUES ($1, $2, $3)
RETURNING message, timestamp, message_id;
INSERT INTO messages (sender, recipient, message, attachment_url)
VALUES ($1, $2, $3, $4)
RETURNING message, timestamp, message_id, attachment_url;
`;
try {
const results = await client.query(query, [sender, recipient, message]);
const results = await client.query(query, [
sender,
recipient,
message,
attachmentUrl,
]);
return results.rows[0];
} catch (e) {
console.error("Failed to insert message ", e);

View File

@@ -57,6 +57,7 @@ const storage = multer.diskStorage({
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
const extension = extname(file.originalname);
const finalName = uniqueSuffix + extension;
file.finalName = finalName;
cb(null, finalName);
},
});
@@ -291,11 +292,10 @@ app.post(
return res.status(400).json({ message: "No file specified" });
}
const { finalName } = req.file;
const url = process.env.ORIGIN;
const url = `${process.env.ORIGIN}/attachments/${finalName}`;
res.json({
message: "File uploaded successfully",
attachmentUrl: req.file,
url: url,
attachment_url: url,
});
},
);

View File

@@ -63,15 +63,28 @@ function initializeSocket(io) {
socket.join(username); // join username room
socket.on("chat message", async (msg, callback) => {
const { message, recipient } = msg;
const { message, recipient, attachment_url } = msg;
const sender = username;
if (!message || !recipient) {
callback({ status: "error", message: "Invalid message or recipient" });
if (!message && !attachment_url) {
callback({
status: "error",
message: "No message or attachment provided",
});
return;
}
if (!recipient) {
callback({ status: "error", message: "No recipient provided" });
return;
}
try {
const insertedMessage = await insertMessage(sender, recipient, message);
const insertedMessage = await insertMessage(
sender,
recipient,
message,
attachment_url,
);
if (!insertedMessage) {
callback({ status: "error", message: "Failed to insert message" });
return;
@@ -83,18 +96,24 @@ function initializeSocket(io) {
io.to(username).to(recipient).emit("chat message", {
sender,
message,
attachment_url,
recipient,
message_id,
});
console.log("(socket) sent on 'chat message' socket: ", {
sender,
message,
attachment_url,
recipient,
timestamp,
message_id,
});
callback({ status: "ok", tempId: msg.tempId });
callback({
status: "ok",
tempId: msg.tempId,
message: "Received message",
});
} catch (e) {
console.error("(socket) Failed to insert message ", e);
callback({ status: "error", message: "Internal server error" });