Spaces:
Runtime error
Runtime error
Commit
·
3b5dd8c
1
Parent(s):
ee1fc35
made working
Browse files- client/src/ChatPage/ChatPage.jsx +3 -21
- client/src/components/Chat/Chat.jsx +50 -22
- client/src/components/Contact/Contact.css +6 -1
- client/src/components/Contact/Contact.jsx +2 -1
- client/src/components/Contacts/Contacts.jsx +8 -4
- client/src/components/SideBar/SideBar.jsx +21 -14
- server/index.ts +68 -22
client/src/ChatPage/ChatPage.jsx
CHANGED
@@ -5,31 +5,13 @@ import { SocketProvider } from '../SocketProvider';
|
|
5 |
|
6 |
function ChatPage() {
|
7 |
|
8 |
-
|
9 |
-
// const socket = io("ws://localhost:3000", {
|
10 |
-
// withCredentials: true,
|
11 |
-
// });
|
12 |
-
|
13 |
-
// socket.on("connect", () => {
|
14 |
-
// console.log("connected", socket.id);
|
15 |
-
// })
|
16 |
-
|
17 |
-
// socket.on("error", () => {
|
18 |
-
// console.log("socket error");
|
19 |
-
// })
|
20 |
-
|
21 |
-
// setInterval(() => {
|
22 |
-
// socket.emit("foobar", "im alive")
|
23 |
-
// }, 2000);
|
24 |
-
|
25 |
-
}, [])
|
26 |
-
|
27 |
const [currentContact, setCurrentContact] = useState({});
|
28 |
return (
|
29 |
<>
|
30 |
<SocketProvider>
|
31 |
-
<SideBar currentContact={currentContact} setCurrentContact={setCurrentContact} />
|
32 |
-
<Chat currentContact={currentContact} />
|
33 |
</SocketProvider>
|
34 |
</>
|
35 |
);
|
|
|
5 |
|
6 |
function ChatPage() {
|
7 |
|
8 |
+
const [contacts, setContacts] = useState([]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
const [currentContact, setCurrentContact] = useState({});
|
10 |
return (
|
11 |
<>
|
12 |
<SocketProvider>
|
13 |
+
<SideBar contacts={contacts} setContacts={setContacts} currentContact={currentContact} setCurrentContact={setCurrentContact} />
|
14 |
+
<Chat contacts={contacts} setContacts={setContacts} currentContact={currentContact} setCurrentContact={setCurrentContact} />
|
15 |
</SocketProvider>
|
16 |
</>
|
17 |
);
|
client/src/components/Chat/Chat.jsx
CHANGED
@@ -6,47 +6,75 @@ import ChatFooter from '../ChatFooter';
|
|
6 |
import { SocketContext } from '../../SocketProvider';
|
7 |
|
8 |
function Chat({
|
|
|
|
|
9 |
currentContact,
|
|
|
10 |
}) {
|
11 |
const [messages, setMessages] = useState([]);
|
12 |
const socket = useContext(SocketContext);
|
13 |
const chatMainRef = useRef();
|
14 |
|
15 |
-
const getMessages = async () => {
|
16 |
-
const res = await fetch(process.env.REACT_APP_BACKEND_URL + `/messages/${currentContact.id}`, { credentials: "include" });
|
17 |
-
const data = await res.json();
|
18 |
-
if (res.ok) {
|
19 |
-
// console.log(data.messages);
|
20 |
-
setMessages(data.messages);
|
21 |
-
}
|
22 |
-
}
|
23 |
-
|
24 |
-
const scrollToBottom = () => {
|
25 |
-
if(chatMainRef.current){
|
26 |
-
chatMainRef.current.scrollTo(0, chatMainRef.current.scrollHeight);
|
27 |
-
}
|
28 |
-
};
|
29 |
-
|
30 |
-
|
31 |
// to get Messages of currently opened chat
|
|
|
32 |
useEffect(() => {
|
|
|
33 |
if (Object.keys(currentContact).length === 0) return;
|
34 |
-
|
35 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
|
37 |
// to add receive_message listener
|
38 |
useEffect(() => {
|
39 |
if (socket) {
|
40 |
socket.on("receive_message", (message) => {
|
41 |
// console.log(message);
|
42 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
});
|
44 |
|
45 |
return () => {
|
46 |
-
socket.off("
|
47 |
};
|
48 |
}
|
49 |
-
}, [socket]);
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
// when ever a chat's messages are updated, scrollToBottom
|
52 |
useEffect(() => {
|
@@ -54,7 +82,7 @@ function Chat({
|
|
54 |
}, [messages]);
|
55 |
|
56 |
|
57 |
-
|
58 |
// Until no chat is selected
|
59 |
if (Object.keys(currentContact).length === 0) {
|
60 |
|
|
|
6 |
import { SocketContext } from '../../SocketProvider';
|
7 |
|
8 |
function Chat({
|
9 |
+
contacts,
|
10 |
+
setContacts,
|
11 |
currentContact,
|
12 |
+
setCurrentContact,
|
13 |
}) {
|
14 |
const [messages, setMessages] = useState([]);
|
15 |
const socket = useContext(SocketContext);
|
16 |
const chatMainRef = useRef();
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
// to get Messages of currently opened chat
|
19 |
+
//--------------------------------------------------------------------------------------------------------------//
|
20 |
useEffect(() => {
|
21 |
+
|
22 |
if (Object.keys(currentContact).length === 0) return;
|
23 |
+
const fetchData = async () => {
|
24 |
+
|
25 |
+
if (!socket) return;
|
26 |
+
// console.log()
|
27 |
+
socket.on("messages", (messages) => {
|
28 |
+
// console.log(messages);
|
29 |
+
setMessages(messages);
|
30 |
+
});
|
31 |
+
|
32 |
+
socket.emit("get_messages", currentContact.id);
|
33 |
+
}
|
34 |
+
fetchData();
|
35 |
+
|
36 |
+
return () => {
|
37 |
+
if (!socket) return;
|
38 |
+
socket.off("messages");
|
39 |
+
}
|
40 |
+
}, [currentContact, socket]);
|
41 |
|
42 |
// to add receive_message listener
|
43 |
useEffect(() => {
|
44 |
if (socket) {
|
45 |
socket.on("receive_message", (message) => {
|
46 |
// console.log(message);
|
47 |
+
// console.log(message.send_from,currentContact.id);
|
48 |
+
// console.log(message.send_from == currentContact.id);
|
49 |
+
if (currentContact && message.send_from == currentContact.id) {
|
50 |
+
setMessages((prev) => [...prev, message]);
|
51 |
+
}
|
52 |
+
else {
|
53 |
+
// contacts.find
|
54 |
+
var updatedContacts = structuredClone(contacts);
|
55 |
+
const idx = updatedContacts.findIndex((contact)=>message.send_from==contact.id);
|
56 |
+
updatedContacts[idx] = {
|
57 |
+
...updatedContacts[idx],
|
58 |
+
last_message:message,
|
59 |
+
}
|
60 |
+
// console.log(contacts);
|
61 |
+
// console.log(updatedContacts);
|
62 |
+
|
63 |
+
setContacts(updatedContacts);
|
64 |
+
}
|
65 |
});
|
66 |
|
67 |
return () => {
|
68 |
+
socket.off("receive_message");
|
69 |
};
|
70 |
}
|
71 |
+
}, [socket,contacts,currentContact]);
|
72 |
+
|
73 |
+
const scrollToBottom = () => {
|
74 |
+
if (chatMainRef.current) {
|
75 |
+
chatMainRef.current.scrollTo(0, chatMainRef.current.scrollHeight);
|
76 |
+
}
|
77 |
+
};
|
78 |
|
79 |
// when ever a chat's messages are updated, scrollToBottom
|
80 |
useEffect(() => {
|
|
|
82 |
}, [messages]);
|
83 |
|
84 |
|
85 |
+
|
86 |
// Until no chat is selected
|
87 |
if (Object.keys(currentContact).length === 0) {
|
88 |
|
client/src/components/Contact/Contact.css
CHANGED
@@ -48,4 +48,9 @@
|
|
48 |
color:rgb(234, 234, 234);
|
49 |
font-size:0.9em;
|
50 |
white-space: nowrap;
|
51 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
48 |
color:rgb(234, 234, 234);
|
49 |
font-size:0.9em;
|
50 |
white-space: nowrap;
|
51 |
+
}
|
52 |
+
.contact__lastmsg.new{
|
53 |
+
/* color:rgb(0, 255, 132); */
|
54 |
+
font-weight: 700;
|
55 |
+
font-size:1.1em;
|
56 |
+
}
|
client/src/components/Contact/Contact.jsx
CHANGED
@@ -7,6 +7,7 @@ function Contact({
|
|
7 |
lastmessage = "",
|
8 |
onClick,
|
9 |
isActive = false,
|
|
|
10 |
}) {
|
11 |
|
12 |
|
@@ -16,7 +17,7 @@ function Contact({
|
|
16 |
<div>
|
17 |
<h4 className='contact__name'>{name}</h4>
|
18 |
{lastmessage != "" &&
|
19 |
-
<p className='contact__lastmsg'>{lastmessage}</p>
|
20 |
}
|
21 |
</div>
|
22 |
</div>
|
|
|
7 |
lastmessage = "",
|
8 |
onClick,
|
9 |
isActive = false,
|
10 |
+
is_new = false,
|
11 |
}) {
|
12 |
|
13 |
|
|
|
17 |
<div>
|
18 |
<h4 className='contact__name'>{name}</h4>
|
19 |
{lastmessage != "" &&
|
20 |
+
<p className={(is_new ? "new":"") + ' contact__lastmsg'}>{lastmessage}</p>
|
21 |
}
|
22 |
</div>
|
23 |
</div>
|
client/src/components/Contacts/Contacts.jsx
CHANGED
@@ -1,6 +1,7 @@
|
|
1 |
-
import React, {
|
2 |
import Contact from '../Contact';
|
3 |
import "./Contacts.css";
|
|
|
4 |
|
5 |
|
6 |
|
@@ -10,8 +11,8 @@ function Contacts({
|
|
10 |
setCurrentContact,
|
11 |
}) {
|
12 |
|
13 |
-
const [activeContact, setActiveContact] = useState({});
|
14 |
-
|
15 |
// handleClick
|
16 |
|
17 |
return (
|
@@ -20,12 +21,15 @@ function Contacts({
|
|
20 |
|
21 |
{
|
22 |
allContacts.map((contact) => (
|
|
|
|
|
23 |
<Contact
|
24 |
key={contact.id}
|
25 |
onClick={() => { setCurrentContact(contact) }}
|
26 |
profile_pic={"logo512.png"}
|
27 |
name={contact.username}
|
28 |
-
lastmessage={
|
|
|
29 |
isActive={currentContact.id == contact.id}
|
30 |
/>
|
31 |
))
|
|
|
1 |
+
import React, { useContext, useState } from 'react'
|
2 |
import Contact from '../Contact';
|
3 |
import "./Contacts.css";
|
4 |
+
import { UserContext } from '../../UserProvider';
|
5 |
|
6 |
|
7 |
|
|
|
11 |
setCurrentContact,
|
12 |
}) {
|
13 |
|
14 |
+
// const [activeContact, setActiveContact] = useState({});
|
15 |
+
const {user} = useContext(UserContext);
|
16 |
// handleClick
|
17 |
|
18 |
return (
|
|
|
21 |
|
22 |
{
|
23 |
allContacts.map((contact) => (
|
24 |
+
// console.log("contact.last_message",contact,contact.last_message),
|
25 |
+
// console.log(user.id),
|
26 |
<Contact
|
27 |
key={contact.id}
|
28 |
onClick={() => { setCurrentContact(contact) }}
|
29 |
profile_pic={"logo512.png"}
|
30 |
name={contact.username}
|
31 |
+
lastmessage={contact.last_message.message}
|
32 |
+
is_new={user.id == contact.last_message.send_to && contact.last_message.is_seen == 0}
|
33 |
isActive={currentContact.id == contact.id}
|
34 |
/>
|
35 |
))
|
client/src/components/SideBar/SideBar.jsx
CHANGED
@@ -1,32 +1,39 @@
|
|
1 |
-
import React, { useEffect, useState } from 'react'
|
2 |
import Search from '../Search';
|
3 |
import Contacts from '../Contacts';
|
4 |
import "./SideBar.css";
|
|
|
|
|
5 |
|
6 |
function SideBar({
|
|
|
|
|
7 |
setCurrentContact,
|
8 |
currentContact,
|
9 |
}) {
|
10 |
-
|
|
|
11 |
|
12 |
useEffect(() => {
|
13 |
|
14 |
const fetchData = async () => {
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
console.error(data);
|
25 |
-
}
|
26 |
}
|
27 |
fetchData();
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
30 |
|
31 |
return (
|
32 |
|
|
|
1 |
+
import React, { useContext, useEffect, useState } from 'react'
|
2 |
import Search from '../Search';
|
3 |
import Contacts from '../Contacts';
|
4 |
import "./SideBar.css";
|
5 |
+
import { SocketContext } from '../../SocketProvider';
|
6 |
+
|
7 |
|
8 |
function SideBar({
|
9 |
+
contacts,
|
10 |
+
setContacts,
|
11 |
setCurrentContact,
|
12 |
currentContact,
|
13 |
}) {
|
14 |
+
|
15 |
+
const socket = useContext(SocketContext);
|
16 |
|
17 |
useEffect(() => {
|
18 |
|
19 |
const fetchData = async () => {
|
20 |
+
|
21 |
+
if(!socket) return;
|
22 |
+
// console.log()
|
23 |
+
socket.on("contacts",(contacts)=>{
|
24 |
+
// console.log(contacts);
|
25 |
+
setContacts(contacts);
|
26 |
+
});
|
27 |
+
|
28 |
+
socket.emit("get_contacts");
|
|
|
|
|
29 |
}
|
30 |
fetchData();
|
31 |
|
32 |
+
return ()=>{
|
33 |
+
if(!socket) return;
|
34 |
+
socket.off("contacts");
|
35 |
+
}
|
36 |
+
}, [socket]);
|
37 |
|
38 |
return (
|
39 |
|
server/index.ts
CHANGED
@@ -217,9 +217,9 @@ app.get("/contacts", isAuthAPIMiddleware, async (req, res) => {
|
|
217 |
|
218 |
// get currentContact's messsages route
|
219 |
app.get("/messages/:userid", isAuthAPIMiddleware, async (req, res) => {
|
220 |
-
|
221 |
// req.query.id
|
222 |
-
|
223 |
var messages = await db.prepare(`select * from messages
|
224 |
where (send_to=? and send_from=?)
|
225 |
or
|
@@ -229,7 +229,7 @@ app.get("/messages/:userid", isAuthAPIMiddleware, async (req, res) => {
|
|
229 |
|
230 |
req.params.userid,
|
231 |
res.locals.user.id,
|
232 |
-
|
233 |
// const messages = await db.prepare("select * from messages").all();
|
234 |
|
235 |
res.json({ "messages": messages });
|
@@ -268,32 +268,77 @@ const isAuth = async (req: Request, res: Response, next) => {
|
|
268 |
|
269 |
io.engine.use(isAuth);
|
270 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
|
272 |
io.on("connection", async (socket) => {
|
273 |
console.log(`socket ${socket.id} connected`);
|
274 |
-
|
275 |
// add user and session to the socket.data object
|
276 |
const sessionId = lucia.readSessionCookie(socket.handshake.headers.cookie ?? "");
|
277 |
const { session, user } = await lucia.validateSession(sessionId as string);
|
278 |
socket.data.user = user;
|
279 |
socket.data.session = session;
|
280 |
|
281 |
-
|
282 |
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
289 |
});
|
|
|
290 |
socket.on("send_message", async (data) => {
|
291 |
// an event was received from the client
|
292 |
|
293 |
const msg_id = generateId(15);
|
294 |
-
|
295 |
const stmt = db.prepare("insert into messages(id,message,send_to,send_from,send_at) values(?,?,?,?,?)");
|
296 |
-
|
297 |
await stmt.run(
|
298 |
msg_id,
|
299 |
data.message,
|
@@ -301,23 +346,24 @@ io.on("connection", async (socket) => {
|
|
301 |
socket.data.user.id,
|
302 |
data.send_at,
|
303 |
);
|
304 |
-
|
305 |
-
console.log("saved message:"
|
306 |
|
307 |
const sockets = await io.fetchSockets();
|
308 |
|
309 |
-
|
310 |
-
sockets.forEach((client)=>{
|
311 |
-
if(client.data.user.id==data.send_to)
|
312 |
-
{
|
313 |
// console.log("heyy");
|
314 |
-
return socket.to(client.id).emit("receive_message",{
|
315 |
...data,
|
316 |
-
"
|
|
|
|
|
317 |
});
|
318 |
}
|
319 |
})
|
320 |
-
|
321 |
});
|
322 |
|
323 |
// upon disconnection
|
|
|
217 |
|
218 |
// get currentContact's messsages route
|
219 |
app.get("/messages/:userid", isAuthAPIMiddleware, async (req, res) => {
|
220 |
+
|
221 |
// req.query.id
|
222 |
+
|
223 |
var messages = await db.prepare(`select * from messages
|
224 |
where (send_to=? and send_from=?)
|
225 |
or
|
|
|
229 |
|
230 |
req.params.userid,
|
231 |
res.locals.user.id,
|
232 |
+
);
|
233 |
// const messages = await db.prepare("select * from messages").all();
|
234 |
|
235 |
res.json({ "messages": messages });
|
|
|
268 |
|
269 |
io.engine.use(isAuth);
|
270 |
|
271 |
+
async function getLastMessage({ user_id, contact_id }: { user_id: string, contact_id: string }) {
|
272 |
+
|
273 |
+
var last_message = await db.prepare(`select * from messages
|
274 |
+
where (send_to=? and send_from=?)
|
275 |
+
or
|
276 |
+
(send_to=? and send_from=?)
|
277 |
+
ORDER BY send_at DESC
|
278 |
+
`).get(
|
279 |
+
user_id,
|
280 |
+
contact_id,
|
281 |
+
|
282 |
+
contact_id,
|
283 |
+
user_id,
|
284 |
+
);
|
285 |
+
|
286 |
+
// console.log(last_message);
|
287 |
+
if (last_message) {
|
288 |
+
return last_message;
|
289 |
+
}
|
290 |
+
else {
|
291 |
+
return {};
|
292 |
+
}
|
293 |
+
|
294 |
+
}
|
295 |
|
296 |
io.on("connection", async (socket) => {
|
297 |
console.log(`socket ${socket.id} connected`);
|
298 |
+
|
299 |
// add user and session to the socket.data object
|
300 |
const sessionId = lucia.readSessionCookie(socket.handshake.headers.cookie ?? "");
|
301 |
const { session, user } = await lucia.validateSession(sessionId as string);
|
302 |
socket.data.user = user;
|
303 |
socket.data.session = session;
|
304 |
|
305 |
+
socket.on("get_contacts", async () => {
|
306 |
|
307 |
+
// get all contacts to client
|
308 |
+
var contacts = await db.prepare("select id,username from users where id!=?").all(socket.data.user.id);
|
309 |
+
contacts = await Promise.all(contacts.map(async (contact: any) => {
|
310 |
+
return { ...contact, last_message: await getLastMessage({ user_id: socket.data.user.id, contact_id: contact.id }) }
|
311 |
+
}))
|
312 |
+
|
313 |
+
// console.log(contacts);
|
314 |
+
socket.emit("contacts", contacts);
|
315 |
+
// socket
|
316 |
+
})
|
317 |
+
|
318 |
+
|
319 |
+
|
320 |
+
socket.on("get_messages", async (contact_id) => {
|
321 |
+
var messages = await db.prepare(`select * from messages
|
322 |
+
where (send_to=? and send_from=?)
|
323 |
+
or
|
324 |
+
(send_to=? and send_from=?)`).all(
|
325 |
+
socket.data.user.id,
|
326 |
+
contact_id,
|
327 |
+
|
328 |
+
contact_id,
|
329 |
+
socket.data.user.id,
|
330 |
+
);
|
331 |
+
|
332 |
+
socket.emit("messages", messages);
|
333 |
});
|
334 |
+
|
335 |
socket.on("send_message", async (data) => {
|
336 |
// an event was received from the client
|
337 |
|
338 |
const msg_id = generateId(15);
|
339 |
+
|
340 |
const stmt = db.prepare("insert into messages(id,message,send_to,send_from,send_at) values(?,?,?,?,?)");
|
341 |
+
|
342 |
await stmt.run(
|
343 |
msg_id,
|
344 |
data.message,
|
|
|
346 |
socket.data.user.id,
|
347 |
data.send_at,
|
348 |
);
|
349 |
+
|
350 |
+
console.log("saved message:", data.message);
|
351 |
|
352 |
const sockets = await io.fetchSockets();
|
353 |
|
354 |
+
|
355 |
+
sockets.forEach((client) => {
|
356 |
+
if (client.data.user.id == data.send_to) {
|
|
|
357 |
// console.log("heyy");
|
358 |
+
return socket.to(client.id).emit("receive_message", {
|
359 |
...data,
|
360 |
+
"send_to": data.send_to,
|
361 |
+
"send_from": socket.data.user.id,
|
362 |
+
"is_seen": 0,
|
363 |
});
|
364 |
}
|
365 |
})
|
366 |
+
|
367 |
});
|
368 |
|
369 |
// upon disconnection
|