diff --git a/package-lock.json b/package-lock.json
index 3b25c8a..8d33643 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -23,6 +23,8 @@
"react-icons": "^5.3.0",
"react-router-dom": "^6.26.1",
"react-toastify": "^10.0.5",
+ "socket.io": "^4.8.0",
+ "socket.io-client": "^4.8.0",
"styled-components": "^6.1.13",
"typescript": "^5.5.4",
"ws": "^8.18.0"
@@ -1853,30 +1855,6 @@
"node": ">=18"
}
},
- "node_modules/@brojs/cli/node_modules/i18next": {
- "version": "23.15.1",
- "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.15.1.tgz",
- "integrity": "sha512-wB4abZ3uK7EWodYisHl/asf8UYEhrI/vj/8aoSsrj/ZDxj4/UXPOa1KvFt1Fq5hkUHquNqwFlDprmjZ8iySgYA==",
- "funding": [
- {
- "type": "individual",
- "url": "https://locize.com"
- },
- {
- "type": "individual",
- "url": "https://locize.com/i18next.html"
- },
- {
- "type": "individual",
- "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
- }
- ],
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "@babel/runtime": "^7.23.2"
- }
- },
"node_modules/@brojs/cli/node_modules/i18next-browser-languagedetector": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
@@ -2691,19 +2669,6 @@
"ijl-cli": "bin/ijl-cli"
}
},
- "node_modules/@ijl/cli/node_modules/@types/react": {
- "version": "17.0.83",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.83.tgz",
- "integrity": "sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "@types/prop-types": "*",
- "@types/scheduler": "^0.16",
- "csstype": "^3.0.2"
- }
- },
"node_modules/@ijl/cli/node_modules/loader-utils": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz",
@@ -2717,35 +2682,6 @@
"node": ">=8.9.0"
}
},
- "node_modules/@ijl/cli/node_modules/react": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
- "integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/@ijl/cli/node_modules/react-dom": {
- "version": "17.0.2",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
- "integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1",
- "scheduler": "^0.20.2"
- },
- "peerDependencies": {
- "react": "17.0.2"
- }
- },
"node_modules/@ijl/cli/node_modules/react-hot-loader": {
"version": "4.13.1",
"resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.1.tgz",
@@ -2774,17 +2710,6 @@
}
}
},
- "node_modules/@ijl/cli/node_modules/scheduler": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz",
- "integrity": "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==",
- "license": "MIT",
- "peer": true,
- "dependencies": {
- "loose-envify": "^1.1.0",
- "object-assign": "^4.1.1"
- }
- },
"node_modules/@ijl/cli/node_modules/source-map": {
"version": "0.7.4",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
@@ -3071,12 +2996,14 @@
"node_modules/@types/cookie": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
- "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q=="
+ "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
+ "license": "MIT"
},
"node_modules/@types/cors": {
"version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
+ "license": "MIT",
"dependencies": {
"@types/node": "*"
}
@@ -3138,14 +3065,6 @@
"@types/react": "*"
}
},
- "node_modules/@types/scheduler": {
- "version": "0.16.8",
- "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
- "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/@types/source-list-map": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/@types/source-list-map/-/source-list-map-0.1.6.tgz",
@@ -3735,6 +3654,7 @@
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
+ "license": "MIT",
"engines": {
"node": "^4.5.0 || >= 5.9"
}
@@ -4364,6 +4284,7 @@
"version": "2.8.5",
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+ "license": "MIT",
"dependencies": {
"object-assign": "^4",
"vary": "^1"
@@ -4783,9 +4704,10 @@
}
},
"node_modules/engine.io": {
- "version": "6.5.5",
- "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz",
- "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==",
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.1.tgz",
+ "integrity": "sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og==",
+ "license": "MIT",
"dependencies": {
"@types/cookie": "^0.4.1",
"@types/cors": "^2.8.12",
@@ -4802,6 +4724,40 @@
"node": ">=10.2.0"
}
},
+ "node_modules/engine.io-client": {
+ "version": "6.6.1",
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.1.tgz",
+ "integrity": "sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.1",
+ "engine.io-parser": "~5.2.1",
+ "ws": "~8.17.1",
+ "xmlhttprequest-ssl": "~2.1.1"
+ }
+ },
+ "node_modules/engine.io-client/node_modules/ws": {
+ "version": "8.17.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
"node_modules/engine.io-parser": {
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
@@ -4814,6 +4770,7 @@
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz",
"integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==",
+ "license": "MIT",
"engines": {
"node": ">= 0.6"
}
@@ -8959,15 +8916,16 @@
}
},
"node_modules/socket.io": {
- "version": "4.7.5",
- "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz",
- "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==",
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.0.tgz",
+ "integrity": "sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA==",
+ "license": "MIT",
"dependencies": {
"accepts": "~1.3.4",
"base64id": "~2.0.0",
"cors": "~2.8.5",
"debug": "~4.3.2",
- "engine.io": "~6.5.2",
+ "engine.io": "~6.6.0",
"socket.io-adapter": "~2.5.2",
"socket.io-parser": "~4.2.4"
},
@@ -9005,6 +8963,21 @@
}
}
},
+ "node_modules/socket.io-client": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.0.tgz",
+ "integrity": "sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw==",
+ "license": "MIT",
+ "dependencies": {
+ "@socket.io/component-emitter": "~3.1.0",
+ "debug": "~4.3.2",
+ "engine.io-client": "~6.6.1",
+ "socket.io-parser": "~4.2.4"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
"node_modules/socket.io-parser": {
"version": "4.2.4",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
@@ -10147,6 +10120,14 @@
}
}
},
+ "node_modules/xmlhttprequest-ssl": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz",
+ "integrity": "sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
diff --git a/package.json b/package.json
index a351a3f..d322cac 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,8 @@
"react-icons": "^5.3.0",
"react-router-dom": "^6.26.1",
"react-toastify": "^10.0.5",
+ "socket.io": "^4.8.0",
+ "socket.io-client": "^4.8.0",
"styled-components": "^6.1.13",
"typescript": "^5.5.4",
"ws": "^8.18.0"
diff --git a/src/backend/chat-server.js b/src/backend/chat-server.js
deleted file mode 100644
index 340aa0f..0000000
--- a/src/backend/chat-server.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const WebSocket = require("ws");
-const wss = new WebSocket.Server({ port: 8080 });
-
-const clients = new Map();
-
-wss.on("connection", (ws, req) => {
- console.log("New client connected");
-
- ws.on("message", (message) => {
- try {
- const parsedMessage = JSON.parse(message);
- if (parsedMessage.type === "register") {
- clients.set(parsedMessage.userId, ws);
- console.log(`User registered: ${parsedMessage.userId}`);
- } else if (parsedMessage.type === "message") {
- const recipientWs = clients.get(parsedMessage.recipientId);
- if (recipientWs) {
- recipientWs.send(
- JSON.stringify({
- senderId: parsedMessage.senderId,
- message: parsedMessage.message,
- timestamp: new Date().toISOString(),
- })
- );
- } else {
- console.error(`User ${parsedMessage.recipientId} is not connected.`);
- }
- }
- } catch (err) {
- console.error("Error processing message:", err.message);
- }
- });
-
- ws.on("close", () => {
- console.log("Client disconnected");
- [...clients.entries()].forEach(([userId, clientWs]) => {
- if (clientWs === ws) {
- clients.delete(userId);
- console.log(`User disconnected: ${userId}`);
- }
- });
- });
-});
diff --git a/src/backend/server.js b/src/backend/server.js
new file mode 100644
index 0000000..1ca3577
--- /dev/null
+++ b/src/backend/server.js
@@ -0,0 +1,31 @@
+const express = require("express");
+const http = require("http");
+const { Server } = require("socket.io");
+require("dotenv").config();
+
+const app = express();
+const server = http.createServer(app);
+const io = new Server(server);
+
+io.on("connection", (socket) => {
+ console.log("New connection:", socket.id);
+
+ // For messages
+ socket.on("sendMessage", (message) => {
+ console.log("Message received:", message);
+ socket.broadcast.emit("receiveMessage", message);
+ });
+
+ socket.on("disconnect", () => {
+ console.log("User disconnected:", socket.id);
+ });
+});
+
+app.get("/", (req, res) => {
+ res.send("Socket.IO Server is running");
+});
+
+const PORT = process.env.PORT || 8099;
+server.listen(PORT, () => {
+ console.log(`Server is running on port ${PORT}`);
+});
diff --git a/src/components/home/ChatsList.jsx b/src/components/home/ChatsList.jsx
index acb1f65..7cccfdc 100644
--- a/src/components/home/ChatsList.jsx
+++ b/src/components/home/ChatsList.jsx
@@ -1,76 +1,92 @@
-import React, {useEffect, useState} from 'react';
+import React, { useEffect, useState } from "react";
import Card from "./Card.jsx";
-import {get} from "../../backend/api";
-import {displayMessage} from "../../backend/notifications/notifications";
-import {MessageType} from "../../backend/notifications/message";
+import { get } from "../../backend/api";
+import { displayMessage } from "../../backend/notifications/notifications";
+import { MessageType } from "../../backend/notifications/message";
const ChatsList = (props) => {
- const { chats } = props;
+ const { chats } = props;
+ const [customChats, setCustomChats] = useState([]);
- const [customChats, setCustomChats] = useState([]);
+ const updateList = async () => {
+ const username = localStorage.getItem("username");
+ if (!username) return null;
- const updateList = async () => {
- const username = localStorage.getItem("username");
- if (!username) {return null;}
+ const updatedChats = await Promise.all(
+ chats.map(async (chat) => {
+ const interlocutorId = chat.id1 === username ? chat.id2 : chat.id1;
- const updatedChats = await Promise.all(
- chats.map(async (chat) => {
- const interlocutorId = chat.id1 === username ? chat.id2 : chat.id1
+ const { ok, data } = await get("/auth/" + interlocutorId);
+ if (!ok) {
+ displayMessage(data.message, MessageType.ERROR);
+ return null;
+ }
- const {ok, data} = await get('/auth/' + interlocutorId);
- if (!ok) {
- displayMessage(data.message, MessageType.ERROR);
- return null;
- }
+ const interlocutor = data.user;
- const interlocutor = data.user;
+ const lastMessage =
+ chat.messages.length > 0
+ ? chat.messages[chat.messages.length - 1]
+ : { data: "", timestamp: new Date(0).toISOString() };
- return {
- id: interlocutorId,
- name: interlocutor.nickname,
- lastMessage: chat.messages.length > 0 ? chat.messages[chat.messages.length - 1].data : "",
- }
- })
- );
+ return {
+ id: interlocutorId,
+ name: interlocutor.nickname,
+ lastMessageData: lastMessage.data,
+ lastMessageTimestamp: lastMessage.timestamp,
+ };
+ })
+ );
- setCustomChats(updatedChats.filter(chat => chat !== null));
- };
+ const validChats = updatedChats.filter((chat) => chat !== null);
- useEffect(() => {updateList().then();}, [chats])
+ validChats.sort(
+ (a, b) =>
+ new Date(b.lastMessageTimestamp) - new Date(a.lastMessageTimestamp)
+ );
+ setCustomChats(validChats);
+ };
- const colorMap = {
- orange: 'FFA500FF',
- aqua: '00FFFFFF',
- crimson: 'DC143CFF',
- red: 'FF0000FF',
- violet: '8A2BE2FF',
- seagreen: '20B2AAFF',
- green: 'ADFF2FFF',
- blue: '0000FFFF',
- pink: 'FF1493FF',
- cyan: '72FAFAFF'
- }
+ useEffect(() => {
+ updateList().then();
+ }, [chats]);
- function getColor(chatId) {
- const keys = Object.keys(colorMap);
- const numericId = Array.from(chatId).reduce((sum, char) => sum + char.charCodeAt(0), 0);
- const index = numericId % keys.length;
- return colorMap[keys[index]];
- }
+ const colorMap = {
+ orange: "FFA500FF",
+ aqua: "00FFFFFF",
+ crimson: "DC143CFF",
+ red: "FF0000FF",
+ violet: "8A2BE2FF",
+ seagreen: "20B2AAFF",
+ green: "ADFF2FFF",
+ blue: "0000FFFF",
+ pink: "FF1493FF",
+ cyan: "72FAFAFF",
+ };
+
+ function getColor(chatId) {
+ const keys = Object.keys(colorMap);
+ const numericId = Array.from(chatId).reduce(
+ (sum, char) => sum + char.charCodeAt(0),
+ 0
+ );
+ const index = numericId % keys.length;
+ return colorMap[keys[index]];
+ }
return (
-
- {customChats.map((item, index) => (
-
- ))}
-
+
+ {customChats.map((item, index) => (
+
+ ))}
+
);
};
diff --git a/src/pages/Chat.jsx b/src/pages/Chat.jsx
index b8ad2ef..cfbbb29 100644
--- a/src/pages/Chat.jsx
+++ b/src/pages/Chat.jsx
@@ -2,9 +2,10 @@ import React, { useEffect, useState, useRef } from "react";
import { useNavigate } from "react-router-dom";
import "./css/Chat.css";
import { FaPaperPlane, FaSmile } from "react-icons/fa";
-import {get, post} from "../backend/api";
-import {displayMessage} from "../backend/notifications/notifications";
-import {MessageType} from "../backend/notifications/message";
+import { get, post } from "../backend/api";
+import { displayMessage } from "../backend/notifications/notifications";
+import { MessageType } from "../backend/notifications/message";
+import io from "socket.io-client";
const emojis = [
"😀",
@@ -88,8 +89,7 @@ const Chat = () => {
const [myId, setMyId] = useState("");
useEffect(() => {
- // const id = parseInt(localStorage.getItem("interlocutorId"), 10) || 0;
- const id = localStorage.getItem("interlocutorId")
+ const id = localStorage.getItem("interlocutorId");
setInterlocutorId(id);
const username = localStorage.getItem("username");
@@ -100,36 +100,24 @@ const Chat = () => {
return () => {};
}
- socket.current = new WebSocket("ws://localhost:8080");
+ socket.current = io("http://localhost:8099");
- socket.current.onopen = () => {
- console.log("WebSocket connected");
- socket.current.send(
- JSON.stringify({ type: "register", userId: "yourUserId" })
- );
- };
+ socket.current.on("receiveMessage", (message) => {
+ setMessages((prev) => [...prev, message]);
+ });
- socket.current.onmessage = (event) => {
- const receivedData = JSON.parse(event.data);
- setMessages((prev) => [...prev, receivedData]);
- };
-
- socket.current.onerror = (event) => {
- console.error("WebSocket error observed:", event);
- };
-
- socket.current.onclose = () => {
- console.log("WebSocket closed");
- };
+ socket.current.on("connect_error", (err) => {
+ console.error("Connection Error:", err.message);
+ });
return () => {
- socket.current.close();
+ socket.current.disconnect();
};
}, []);
useEffect(() => {
retrieveMessages().then();
- }, [myId, interlocutorId])
+ }, [myId, interlocutorId]);
useEffect(() => {
if (chatRef.current) {
@@ -137,25 +125,24 @@ const Chat = () => {
}
}, [messages]);
- // The function for sending message to the DB
- async function sendMessageToDB (messageData) {
- const { ok, data } = post('/chat/message/' + myId + '/' + interlocutorId, { message: messageData });
-
+ async function sendMessageToDB(messageData) {
+ const { ok, data } = await post(
+ "/chat/message/" + myId + "/" + interlocutorId,
+ { message: messageData }
+ );
if (!ok) {
displayMessage(data.message, MessageType.ERROR);
}
}
- // The function retrieves messages from the DB for the current chat
- async function retrieveMessages () {
- if (!myId || !interlocutorId) {return;}
- const { ok, data } = await get('/chat/item/' + myId + '/' + interlocutorId);
+ async function retrieveMessages() {
+ if (!myId || !interlocutorId) return;
+ const { ok, data } = await get("/chat/item/" + myId + "/" + interlocutorId);
if (!ok) {
displayMessage(data.message, MessageType.ERROR);
return;
}
-
setMessages(data.chat.messages);
}
@@ -165,15 +152,11 @@ const Chat = () => {
senderId: myId,
recipientId: interlocutorId,
data: newMessage,
- timestamp: new Date().toLocaleTimeString(),
+ timestamp: new Date().toLocaleString(),
};
- socket.current.send(JSON.stringify(messageData));
+ socket.current.emit("sendMessage", messageData);
setMessages((prev) => [...prev, messageData]);
-
sendMessageToDB(messageData).then();
-
- console.log('format:', messageData);
-
setNewMessage("");
}
};
@@ -198,8 +181,7 @@ const Chat = () => {
className="home-button"
>
Home
- {" "}
- {}
+
{messages.map((msg, index) => (
@@ -210,8 +192,7 @@ const Chat = () => {
}`}
>
- {msg.senderId === myId ? "You" : "They"}:{" "}
- {msg.data}
+ {msg.senderId === myId ? "You" : "They"}: {msg.data}
{msg.timestamp}
diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx
index 2158801..3b8fed1 100644
--- a/src/pages/Home.jsx
+++ b/src/pages/Home.jsx
@@ -1,77 +1,86 @@
-import React, {useEffect, useState} from "react";
+import React, { useEffect, useState } from "react";
import HomeTitle from "../components/home/HomeTitle.jsx";
import ChatsList from "../components/home/ChatsList.jsx";
import Header from "../components/home/Header.jsx";
-import {displayMessage} from "../backend/notifications/notifications";
-import {MessageType} from "../backend/notifications/message";
-import {get, post} from "../backend/api";
+import { displayMessage } from "../backend/notifications/notifications";
+import { MessageType } from "../backend/notifications/message";
+import { get, post } from "../backend/api";
import InputField from "../components/reg/InputField.jsx";
import Search from "../components/home/Search.jsx";
-import {URLs} from "../__data__/urls";
+import { URLs } from "../__data__/urls";
const Home = () => {
- const [chats, setChats] = useState([])
- const [interlocutor, setInterlocutor] = useState("")
+ const [chats, setChats] = useState([]);
+ const [interlocutor, setInterlocutor] = useState("");
- async function retrieveChats() {
- const username = localStorage.getItem("username");
- if (!username) {
- displayMessage("You're not logged in!", MessageType.WARN);
- return;
- }
-
- const {ok, data} = await get('/chat/list/' + username);
- if (!ok) {
- displayMessage(data.message, MessageType.ERROR);
- return;
- }
- setChats(data.chats);
+ async function retrieveChats() {
+ const username = localStorage.getItem("username");
+ if (!username) {
+ displayMessage("You're not logged in!", MessageType.WARN);
+ return;
}
- async function createChat(alias) {
- const username = localStorage.getItem("username");
- if (!username) {
- displayMessage("You're not logged in!", MessageType.WARN);
- return;
- }
-
- displayMessage("Sent", MessageType.INFO);
-
- const {ok, data} = await post('/chat/item/' + username + '/' + alias);
- if (!ok) {
- displayMessage(data.message, MessageType.ERROR);
- } else {
- localStorage.setItem('message', 'Successfully opened chat!');
- localStorage.setItem('interlocutorId', alias);
- window.location.href = URLs.chat.url;
- }
+ const { ok, data } = await get("/chat/list/" + username);
+ if (!ok) {
+ displayMessage(data.message, MessageType.ERROR);
+ return;
}
- useEffect(() => {retrieveChats().then()}, [])
+ const sortedChats = data.chats.sort((a, b) => {
+ const lastMessageA = new Date(a.lastMessageTimestamp);
+ const lastMessageB = new Date(b.lastMessageTimestamp);
+ return lastMessageB - lastMessageA;
+ });
- return (
-
-
-
-
+ setChats(sortedChats);
+ }
-
+ async function createChat(alias) {
+ const username = localStorage.getItem("username");
+ if (!username) {
+ displayMessage("You're not logged in!", MessageType.WARN);
+ return;
+ }
-
-
-
+ displayMessage("Sent", MessageType.INFO);
-
+ const { ok, data } = await post("/chat/item/" + username + "/" + alias);
+ if (!ok) {
+ displayMessage(data.message, MessageType.ERROR);
+ } else {
+ localStorage.setItem("message", "Successfully opened chat!");
+ localStorage.setItem("interlocutorId", alias);
+ window.location.href = URLs.chat.url;
+ }
+ }
- Your chats
-
+ useEffect(() => {
+ retrieveChats();
+ }, []);
+
+ return (
+
+
+
- )
-}
-export default Home
\ No newline at end of file
+
+
+
+
+
+
+
+
+
Your chats
+
+
+ );
+};
+
+export default Home;
diff --git a/src/pages/css/Chat.css b/src/pages/css/Chat.css
index 4d39650..1eb8c80 100644
--- a/src/pages/css/Chat.css
+++ b/src/pages/css/Chat.css
@@ -1,3 +1,7 @@
+body {
+ background: linear-gradient(to right, #e0f7fa, #fffde7);
+}
+
.chat-container {
display: flex;
flex-direction: column;
@@ -11,10 +15,13 @@
}
.chat-header {
- padding: 10px;
+ padding: 15px;
background-color: #007bff;
color: white;
text-align: center;
+ font-weight: bold;
+ letter-spacing: 1px;
+ border-bottom: 2px solid #0056b3;
}
.chat-messages {
@@ -24,6 +31,7 @@
padding: 10px;
overflow-y: auto;
background-color: #fff;
+ max-height: 400px;
}
.message-bubble {
@@ -33,6 +41,12 @@
max-width: 70%;
word-wrap: break-word;
display: inline-block;
+ box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
+ transition: transform 0.2s;
+}
+
+.message-bubble:hover {
+ transform: translateY(-2px);
}
.sent {
@@ -58,8 +72,9 @@
.message-timestamp {
font-size: 10px;
- color: #999;
- margin-top: 5px;
+ color: black;
+ text-align: right;
+ margin-top: 4px;
display: block;
}
diff --git a/stubs/api/chat/chats.json b/stubs/api/chat/chats.json
index cc31ed4..4e9d173 100644
--- a/stubs/api/chat/chats.json
+++ b/stubs/api/chat/chats.json
@@ -7,25 +7,25 @@
"data": "Hello Bob!",
"senderId": "alice",
"recipientId": "bobsm",
- "timestamp": "07:00:00 AM"
+ "timestamp": "09.10.2024 07:00:00"
},
{
"data": "Hey Alice, how are you?",
"senderId": "bobsm",
"recipientId": "alice",
- "timestamp": "07:05:00 AM"
+ "timestamp": "09.10.2024 07:05:00"
},
{
"data": "I'm good, thanks for asking.",
"senderId": "alice",
"recipientId": "bobsm",
- "timestamp": "07:10:00 AM"
+ "timestamp": "09.10.2024 07:10:00"
},
{
"data": "Glad to hear!",
"senderId": "bobsm",
"recipientId": "alice",
- "timestamp": "07:15:00 AM"
+ "timestamp": "09.10.2024 07:15:00"
}
]
},
@@ -37,25 +37,25 @@
"data": "How's the project going?",
"senderId": "alice",
"recipientId": "charl",
- "timestamp": "07:20:00 AM"
+ "timestamp": "09.10.2024 07:20:00"
},
{
"data": "It's coming along, almost done!",
"senderId": "charl",
"recipientId": "alice",
- "timestamp": "07:25:00 AM"
+ "timestamp": "09.10.2024 07:25:00"
},
{
"data": "That's great to hear!",
"senderId": "alice",
"recipientId": "charl",
- "timestamp": "07:30:00 AM"
+ "timestamp": "09.10.2024 07:30:00"
},
{
"data": "Thanks for checking in.",
"senderId": "charl",
"recipientId": "alice",
- "timestamp": "07:35:00 AM"
+ "timestamp": "09.10.2024 07:35:00"
}
]
},
@@ -67,55 +67,25 @@
"data": "Did you get the files?",
"senderId": "david",
"recipientId": "alice",
- "timestamp": "07:40:00 AM"
+ "timestamp": "09.10.2024 07:40:00"
},
{
"data": "Yes, I did. Thank you!",
"senderId": "alice",
"recipientId": "david",
- "timestamp": "07:45:00 AM"
+ "timestamp": "09.10.2024 07:45:00"
},
{
"data": "You're welcome.",
"senderId": "david",
"recipientId": "alice",
- "timestamp": "07:50:00 AM"
+ "timestamp": "09.10.2024 07:50:00"
},
{
"data": "Let me know if you need anything else.",
"senderId": "alice",
"recipientId": "david",
- "timestamp": "07:55:00 AM"
- }
- ]
- },
- {
- "id1": "alice",
- "id2": "evead",
- "messages": [
- {
- "data": "Eve, do you have the meeting details?",
- "senderId": "alice",
- "recipientId": "evead",
- "timestamp": "08:00:00 AM"
- },
- {
- "data": "Yes, I just sent them to you.",
- "senderId": "evead",
- "recipientId": "alice",
- "timestamp": "08:05:00 AM"
- },
- {
- "data": "Got it, thanks!",
- "senderId": "alice",
- "recipientId": "evead",
- "timestamp": "08:10:00 AM"
- },
- {
- "data": "You're welcome.",
- "senderId": "evead",
- "recipientId": "alice",
- "timestamp": "08:15:00 AM"
+ "timestamp": "09.10.2024 07:55:00"
}
]
},
@@ -127,25 +97,25 @@
"data": "Can you review this document for me?",
"senderId": "alice",
"recipientId": "frank",
- "timestamp": "08:20:00 AM"
+ "timestamp": "09.10.2024 08:20:00"
},
{
"data": "Sure, I'll take a look.",
"senderId": "frank",
"recipientId": "alice",
- "timestamp": "08:25:00 AM"
+ "timestamp": "09.10.2024 08:25:00"
},
{
"data": "Thanks, much appreciated!",
"senderId": "alice",
"recipientId": "frank",
- "timestamp": "08:30:00 AM"
+ "timestamp": "09.10.2024 08:30:00"
},
{
"data": "No problem.",
"senderId": "frank",
"recipientId": "alice",
- "timestamp": "08:35:00 AM"
+ "timestamp": "09.10.2024 08:35:00"
}
]
},
@@ -157,25 +127,25 @@
"data": "Hey Grace, let's meet up for coffee!",
"senderId": "alice",
"recipientId": "grace",
- "timestamp": "08:40:00 AM"
+ "timestamp": "09.10.2024 08:40:00"
},
{
"data": "Sounds good, when are you free?",
"senderId": "grace",
"recipientId": "alice",
- "timestamp": "08:45:00 AM"
+ "timestamp": "09.10.2024 08:45:00"
},
{
"data": "How about tomorrow afternoon?",
"senderId": "alice",
"recipientId": "grace",
- "timestamp": "08:50:00 AM"
+ "timestamp": "09.10.2024 08:50:00"
},
{
"data": "Works for me!",
"senderId": "grace",
"recipientId": "alice",
- "timestamp": "08:55:00 AM"
+ "timestamp": "09.10.2024 08:55:00"
}
]
},
@@ -187,25 +157,25 @@
"data": "Hannah, do you have a moment?",
"senderId": "alice",
"recipientId": "hanna",
- "timestamp": "09:00:00 AM"
+ "timestamp": "09.10.2024 09:00:00"
},
{
"data": "Sure, what's up?",
"senderId": "hanna",
"recipientId": "alice",
- "timestamp": "09:05:00 AM"
+ "timestamp": "09.10.2024 09:05:00"
},
{
"data": "Just wanted to check on the report.",
"senderId": "alice",
"recipientId": "hanna",
- "timestamp": "09:10:00 AM"
+ "timestamp": "09.10.2024 09:10:00"
},
{
"data": "I'll send it soon.",
"senderId": "hanna",
"recipientId": "alice",
- "timestamp": "09:15:00 AM"
+ "timestamp": "09.10.2024 09:15:00"
}
]
},
@@ -217,25 +187,25 @@
"data": "Ian, have you completed the review?",
"senderId": "alice",
"recipientId": "ianda",
- "timestamp": "09:20:00 AM"
+ "timestamp": "09.10.2024 09:20:00"
},
{
"data": "Yes, I sent my feedback.",
"senderId": "ianda",
"recipientId": "alice",
- "timestamp": "09:25:00 AM"
+ "timestamp": "09.10.2024 09:25:00"
},
{
"data": "Thanks for that.",
"senderId": "alice",
"recipientId": "ianda",
- "timestamp": "09:30:00 AM"
+ "timestamp": "09.10.2024 09:30:00"
},
{
"data": "Anytime!",
"senderId": "ianda",
"recipientId": "alice",
- "timestamp": "09:35:00 AM"
+ "timestamp": "09.10.2024 09:35:00"
}
]
},
@@ -247,25 +217,25 @@
"data": "Jill, let's schedule a catch-up meeting.",
"senderId": "alice",
"recipientId": "jillt",
- "timestamp": "09:40:00 AM"
+ "timestamp": "09.10.2024 09:40:00"
},
{
"data": "Sounds good, when works for you?",
"senderId": "jillt",
"recipientId": "alice",
- "timestamp": "09:45:00 AM"
+ "timestamp": "09.10.2024 09:45:00"
},
{
"data": "Tomorrow afternoon?",
"senderId": "alice",
"recipientId": "jillt",
- "timestamp": "09:50:00 AM"
+ "timestamp": "09.10.2024 09:50:00"
},
{
"data": "That works for me!",
"senderId": "jillt",
"recipientId": "alice",
- "timestamp": "09:55:00 AM"
+ "timestamp": "09.10.2024 09:55:00"
}
]
},
@@ -277,25 +247,25 @@
"data": "Eve, did you send the schedule?",
"senderId": "alice",
"recipientId": "evead",
- "timestamp": "10:00:00 AM"
+ "timestamp": "09.10.2024 10:00:00"
},
{
"data": "Yes, just sent it.",
"senderId": "evead",
"recipientId": "alice",
- "timestamp": "10:05:00 AM"
+ "timestamp": "09.10.2024 10:05:00"
},
{
"data": "Thanks, much appreciated!",
"senderId": "alice",
"recipientId": "evead",
- "timestamp": "10:10:00 AM"
+ "timestamp": "09.10.2024 10:10:00"
},
{
"data": "No problem!",
"senderId": "evead",
"recipientId": "alice",
- "timestamp": "10:15:00 AM"
+ "timestamp": "09.10.2024 10:15:00"
}
]
},
@@ -307,25 +277,25 @@
"data": "How's everything going?",
"senderId": "bobsm",
"recipientId": "charl",
- "timestamp": "10:20:00 AM"
+ "timestamp": "09.10.2024 10:20:00"
},
{
"data": "Pretty good, how about you?",
"senderId": "charl",
"recipientId": "bobsm",
- "timestamp": "10:25:00 AM"
+ "timestamp": "09.10.2024 10:25:00"
},
{
"data": "Can't complain!",
"senderId": "bobsm",
"recipientId": "charl",
- "timestamp": "10:30:00 AM"
+ "timestamp": "09.10.2024 10:30:00"
},
{
"data": "Glad to hear that.",
"senderId": "charl",
"recipientId": "bobsm",
- "timestamp": "10:35:00 AM"
+ "timestamp": "09.10.2024 10:35:00"
}
]
},
@@ -337,25 +307,25 @@
"data": "Can you send the report?",
"senderId": "bobsm",
"recipientId": "david",
- "timestamp": "10:40:00 AM"
+ "timestamp": "09.10.2024 10:40:00"
},
{
"data": "I'll send it in an hour.",
"senderId": "david",
"recipientId": "bobsm",
- "timestamp": "10:45:00 AM"
+ "timestamp": "09.10.2024 10:45:00"
},
{
"data": "Perfect, thanks.",
"senderId": "bobsm",
"recipientId": "david",
- "timestamp": "10:50:00 AM"
+ "timestamp": "09.10.2024 10:50:00"
},
{
"data": "No problem.",
"senderId": "david",
"recipientId": "bobsm",
- "timestamp": "10:55:00 AM"
+ "timestamp": "09.10.2024 10:55:00"
}
]
},
@@ -367,25 +337,25 @@
"data": "Hey Eve, how's it going?",
"senderId": "charl",
"recipientId": "evead",
- "timestamp": "11:00:00 AM"
+ "timestamp": "09.10.2024 11:00:00"
},
{
"data": "Good, how about you?",
"senderId": "evead",
"recipientId": "charl",
- "timestamp": "11:05:00 AM"
+ "timestamp": "09.10.2024 11:05:00"
},
{
"data": "Can't complain!",
"senderId": "charl",
"recipientId": "evead",
- "timestamp": "11:10:00 AM"
+ "timestamp": "09.10.2024 11:10:00"
},
{
"data": "Glad to hear.",
"senderId": "evead",
"recipientId": "charl",
- "timestamp": "11:15:00 AM"
+ "timestamp": "09.10.2024 11:15:00"
}
]
},
@@ -397,25 +367,25 @@
"data": "Do you have time to talk today?",
"senderId": "charl",
"recipientId": "frank",
- "timestamp": "11:20:00 AM"
+ "timestamp": "09.10.2024 11:20:00"
},
{
"data": "I have a meeting, but I can chat afterward.",
"senderId": "frank",
"recipientId": "charl",
- "timestamp": "11:25:00 AM"
+ "timestamp": "09.10.2024 11:25:00"
},
{
"data": "Sounds good.",
"senderId": "charl",
"recipientId": "frank",
- "timestamp": "11:30:00 AM"
+ "timestamp": "09.10.2024 11:30:00"
},
{
"data": "I'll message you after.",
"senderId": "frank",
"recipientId": "charl",
- "timestamp": "11:35:00 AM"
+ "timestamp": "09.10.2024 11:35:00"
}
]
},
@@ -427,25 +397,25 @@
"data": "Did you review the document?",
"senderId": "david",
"recipientId": "frank",
- "timestamp": "11:40:00 AM"
+ "timestamp": "09.10.2024 11:40:00"
},
{
"data": "Yes, it's all good.",
"senderId": "frank",
"recipientId": "david",
- "timestamp": "11:45:00 AM"
+ "timestamp": "09.10.2024 11:45:00"
},
{
"data": "Great, thanks for the quick turnaround!",
"senderId": "david",
"recipientId": "frank",
- "timestamp": "11:50:00 AM"
+ "timestamp": "09.10.2024 11:50:00"
},
{
"data": "No worries!",
"senderId": "frank",
"recipientId": "david",
- "timestamp": "11:55:00 AM"
+ "timestamp": "09.10.2024 11:55:00"
}
]
},
@@ -457,25 +427,25 @@
"data": "Grace, can you send the updated schedule?",
"senderId": "david",
"recipientId": "grace",
- "timestamp": "12:00:00 PM"
+ "timestamp": "09.10.2024 12:00:00"
},
{
"data": "Yes, I'll send it in a few minutes.",
"senderId": "grace",
"recipientId": "david",
- "timestamp": "12:05:00 PM"
+ "timestamp": "09.10.2024 12:05:00"
},
{
"data": "Thanks, much appreciated!",
"senderId": "david",
"recipientId": "grace",
- "timestamp": "12:10:00 PM"
+ "timestamp": "09.10.2024 12:10:00"
},
{
"data": "You're welcome!",
"senderId": "grace",
"recipientId": "david",
- "timestamp": "12:15:00 PM"
+ "timestamp": "09.10.2024 12:15:00"
}
]
},
@@ -487,25 +457,25 @@
"data": "How are you today?",
"senderId": "frank",
"recipientId": "grace",
- "timestamp": "12:20:00 PM"
+ "timestamp": "09.10.2024 12:20:00"
},
{
"data": "I'm doing well, thanks for asking.",
"senderId": "grace",
"recipientId": "frank",
- "timestamp": "12:25:00 PM"
+ "timestamp": "09.10.2024 12:25:00"
},
{
"data": "Glad to hear that.",
"senderId": "frank",
"recipientId": "grace",
- "timestamp": "12:30:00 PM"
+ "timestamp": "09.10.2024 12:30:00"
},
{
"data": "How about you?",
"senderId": "grace",
"recipientId": "frank",
- "timestamp": "12:35:00 PM"
+ "timestamp": "09.10.2024 12:35:00"
}
]
},
@@ -517,25 +487,25 @@
"data": "Did you attend the meeting?",
"senderId": "frank",
"recipientId": "hanna",
- "timestamp": "12:40:00 PM"
+ "timestamp": "09.10.2024 12:40:00"
},
{
"data": "Yes, it was productive.",
"senderId": "hanna",
"recipientId": "frank",
- "timestamp": "12:45:00 PM"
+ "timestamp": "09.10.2024 12:45:00"
},
{
"data": "Good to hear!",
"senderId": "frank",
"recipientId": "hanna",
- "timestamp": "12:50:00 PM"
+ "timestamp": "09.10.2024 12:50:00"
},
{
"data": "Indeed, lots to follow up on.",
"senderId": "hanna",
"recipientId": "frank",
- "timestamp": "12:55:00 PM"
+ "timestamp": "09.10.2024 12:55:00"
}
]
},
@@ -547,25 +517,25 @@
"data": "Can we meet later today?",
"senderId": "grace",
"recipientId": "hanna",
- "timestamp": "01:00:00 PM"
+ "timestamp": "09.10.2024 01:00:00"
},
{
"data": "Sure, what's a good time?",
"senderId": "hanna",
"recipientId": "grace",
- "timestamp": "01:05:00 PM"
+ "timestamp": "09.10.2024 01:05:00"
},
{
- "data": "How about 3 PM?",
+ "data": "How about 3?",
"senderId": "grace",
"recipientId": "hanna",
- "timestamp": "01:10:00 PM"
+ "timestamp": "09.10.2024 01:10:00"
},
{
"data": "Works for me.",
"senderId": "hanna",
"recipientId": "grace",
- "timestamp": "01:15:00 PM"
+ "timestamp": "09.10.2024 01:15:00"
}
]
},
@@ -577,25 +547,25 @@
"data": "Ian, did you get the message I sent?",
"senderId": "grace",
"recipientId": "ianda",
- "timestamp": "01:20:00 PM"
+ "timestamp": "09.10.2024 01:20:00"
},
{
"data": "Yes, I'll respond soon.",
"senderId": "ianda",
"recipientId": "grace",
- "timestamp": "01:25:00 PM"
+ "timestamp": "09.10.2024 01:25:00"
},
{
"data": "Thanks, appreciate it!",
"senderId": "grace",
"recipientId": "ianda",
- "timestamp": "01:30:00 PM"
+ "timestamp": "09.10.2024 01:30:00"
},
{
"data": "You're welcome!",
"senderId": "ianda",
"recipientId": "grace",
- "timestamp": "01:35:00 PM"
+ "timestamp": "09.10.2024 01:35:00"
}
]
},
@@ -607,25 +577,25 @@
"data": "Ian, do you have a minute?",
"senderId": "hanna",
"recipientId": "ianda",
- "timestamp": "01:40:00 PM"
+ "timestamp": "09.10.2024 01:40:00"
},
{
"data": "Yes, what do you need?",
"senderId": "ianda",
"recipientId": "hanna",
- "timestamp": "01:45:00 PM"
+ "timestamp": "09.10.2024 01:45:00"
},
{
"data": "Just a quick update on the project.",
"senderId": "hanna",
"recipientId": "ianda",
- "timestamp": "01:50:00 PM"
+ "timestamp": "09.10.2024 01:50:00"
},
{
"data": "I'll email you the details.",
"senderId": "ianda",
"recipientId": "hanna",
- "timestamp": "01:55:00 PM"
+ "timestamp": "09.10.2024 01:55:00"
}
]
},
@@ -637,25 +607,25 @@
"data": "Jill, can we talk tomorrow?",
"senderId": "hanna",
"recipientId": "jillt",
- "timestamp": "02:00:00 PM"
+ "timestamp": "09.10.2024 02:00:00"
},
{
- "data": "Yes, I'm free after 2 PM.",
+ "data": "Yes, I'm free after 2.",
"senderId": "jillt",
"recipientId": "hanna",
- "timestamp": "02:05:00 PM"
+ "timestamp": "09.10.2024 02:05:00"
},
{
"data": "Perfect, see you then.",
"senderId": "hanna",
"recipientId": "jillt",
- "timestamp": "02:10:00 PM"
+ "timestamp": "09.10.2024 02:10:00"
},
{
"data": "Looking forward to it.",
"senderId": "jillt",
"recipientId": "hanna",
- "timestamp": "02:15:00 PM"
+ "timestamp": "09.10.2024 02:15:00"
}
]
},
@@ -667,25 +637,25 @@
"data": "Jill, I have the files you requested.",
"senderId": "ianda",
"recipientId": "jillt",
- "timestamp": "02:20:00 PM"
+ "timestamp": "09.10.2024 02:20:00"
},
{
"data": "Thanks, please send them over.",
"senderId": "jillt",
"recipientId": "ianda",
- "timestamp": "02:25:00 PM"
+ "timestamp": "09.10.2024 02:25:00"
},
{
"data": "I'll send them right now.",
"senderId": "ianda",
"recipientId": "jillt",
- "timestamp": "02:30:00 PM"
+ "timestamp": "09.10.2024 02:30:00"
},
{
"data": "Great, thanks again!",
"senderId": "jillt",
"recipientId": "ianda",
- "timestamp": "02:35:00 PM"
+ "timestamp": "09.10.2024 02:35:00"
}
]
}