Anuj-Panthri commited on
Commit
f1b8b13
·
1 Parent(s): 35f15f5

added new contact update feature

Browse files
client/src/App.js CHANGED
@@ -4,7 +4,7 @@ import ChatPage from './ChatPage';
4
  import LoginPage from './LoginPage';
5
  import SignupPage from './SignupPage';
6
  import PrivateRoutes from './PrivateRoutes';
7
- import { UserProvider } from './UserProvider';
8
 
9
  function App() {
10
 
 
4
  import LoginPage from './LoginPage';
5
  import SignupPage from './SignupPage';
6
  import PrivateRoutes from './PrivateRoutes';
7
+ import { UserProvider } from './contexts/UserProvider';
8
 
9
  function App() {
10
 
client/src/ChatPage/ChatPage.jsx CHANGED
@@ -1,17 +1,17 @@
1
  import React, { useEffect, useState } from 'react';
2
  import Chat from '../components/Chat';
3
  import SideBar from '../components/SideBar';
4
- import { SocketProvider } from '../SocketProvider';
 
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
  );
 
1
  import React, { useEffect, useState } from 'react';
2
  import Chat from '../components/Chat';
3
  import SideBar from '../components/SideBar';
4
+ import { SocketProvider } from '../contexts/SocketProvider';
5
+ import { ChatProvider } from '../contexts/ChatProvider';
6
 
7
  function ChatPage() {
 
 
 
8
  return (
9
  <>
10
  <SocketProvider>
11
+ <ChatProvider>
12
+ <SideBar />
13
+ <Chat />
14
+ </ChatProvider>
15
  </SocketProvider>
16
  </>
17
  );
client/src/PrivateRoutes.jsx CHANGED
@@ -1,6 +1,6 @@
1
  import React, { useState, useEffect, useContext } from 'react'
2
  import { Outlet, Navigate } from "react-router-dom";
3
- import { UserContext } from './UserProvider';
4
 
5
  function PrivateRoutes() {
6
 
 
1
  import React, { useState, useEffect, useContext } from 'react'
2
  import { Outlet, Navigate } from "react-router-dom";
3
+ import { UserContext } from './contexts/UserProvider';
4
 
5
  function PrivateRoutes() {
6
 
client/src/components/Chat/Chat.jsx CHANGED
@@ -3,23 +3,34 @@ import "./Chat.css";
3
  import ChatHeader from '../ChatHeader';
4
  import ChatMain from '../ChatMain';
5
  import ChatFooter from '../ChatFooter';
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;
@@ -29,7 +40,7 @@ function Chat({
29
  setMessages(messages);
30
  });
31
 
32
- socket.emit("get_messages", currentContact.id);
33
  }
34
  fetchData();
35
 
@@ -37,38 +48,41 @@ function Chat({
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) {
@@ -84,7 +98,7 @@ function Chat({
84
 
85
 
86
  // Until no chat is selected
87
- if (Object.keys(currentContact).length === 0) {
88
 
89
  return (
90
  <div className='chat_dummy'>
@@ -93,12 +107,14 @@ function Chat({
93
  )
94
  }
95
 
 
 
96
  // once a chat is selected
97
- return (
98
  <div className='chat'>
99
- <ChatHeader name={currentContact.username} />
100
  <ChatMain messages={messages} ref={chatMainRef} />
101
- <ChatFooter currentContactId={currentContact.id} setMessages={setMessages} />
102
  </div>
103
  )
104
  }
 
3
  import ChatHeader from '../ChatHeader';
4
  import ChatMain from '../ChatMain';
5
  import ChatFooter from '../ChatFooter';
6
+ import { SocketContext } from '../../contexts/SocketProvider';
7
+ import { ChatContext } from '../../contexts/ChatProvider';
8
+ import { UserContext } from '../../contexts/UserProvider';
9
+
10
+ function Chat({ }) {
11
+
12
+ const {
13
+ contacts,
14
+ setContacts,
15
+ lastMessages,
16
+ setLastMessages,
17
+ currentChat,
18
+ } = useContext(ChatContext);
19
+
20
  const [messages, setMessages] = useState([]);
21
  const socket = useContext(SocketContext);
22
+ const {user} = useContext(UserContext);
23
  const chatMainRef = useRef();
24
+
25
+
26
+
27
 
28
  // to get Messages of currently opened chat
29
  //--------------------------------------------------------------------------------------------------------------//
30
  useEffect(() => {
31
 
32
+ if (Object.keys(currentChat).length === 0) return;
33
+
34
  const fetchData = async () => {
35
 
36
  if (!socket) return;
 
40
  setMessages(messages);
41
  });
42
 
43
+ socket.emit("get_messages", currentChat.id);
44
  }
45
  fetchData();
46
 
 
48
  if (!socket) return;
49
  socket.off("messages");
50
  }
51
+ }, [currentChat, socket]);
52
 
53
  // to add receive_message listener
54
  useEffect(() => {
55
  if (socket) {
56
  socket.on("receive_message", (message) => {
57
+ if (message.send_from == currentChat.id || message.send_from == user.id) {
 
 
 
58
  setMessages((prev) => [...prev, message]);
59
  }
60
+
61
+ const ismessageOfContact = (contact) => (contact.id == message.send_to) || (contact.id == message.send_from);
62
+ var updatedContacts = contacts.map((contact) => (
63
+ ismessageOfContact(contact) ?
64
+ { ...contact, last_message: message } : contact
65
+ ));
66
+
67
+ updatedContacts.sort((a,b)=>b.last_message.send_at - a.last_message.send_at);
68
+ // console.log(updatedContacts);
69
+
70
+ setContacts(updatedContacts);
71
+
72
+ // if message from a new Contact
73
+ const contact = contacts.find(contact=>contact.id==message.send_from);
74
+ if(!contact && message.send_from !=user.id){
75
+ socket.emit("get_contact",message.send_from);
76
  }
77
+
78
  });
79
 
80
+
81
  return () => {
82
  socket.off("receive_message");
83
  };
84
  }
85
+ }, [socket, contacts, currentChat]);
86
 
87
  const scrollToBottom = () => {
88
  if (chatMainRef.current) {
 
98
 
99
 
100
  // Until no chat is selected
101
+ if (Object.keys(currentChat).length === 0) {
102
 
103
  return (
104
  <div className='chat_dummy'>
 
107
  )
108
  }
109
 
110
+ // console.log("currentChat",currentChat);
111
+ // console.log("currentChat",currentChat.id);
112
  // once a chat is selected
113
+ return (
114
  <div className='chat'>
115
+ <ChatHeader name={currentChat.username} />
116
  <ChatMain messages={messages} ref={chatMainRef} />
117
+ <ChatFooter currentChatId={currentChat.id} />
118
  </div>
119
  )
120
  }
client/src/components/ChatFooter/ChatFooter.jsx CHANGED
@@ -1,13 +1,12 @@
1
  import React, { useContext, useEffect, useRef } from 'react'
2
  import "./ChatFooter.css";
3
  import { PaperAirplaneIcon, PhotoIcon, PaperClipIcon, FaceSmileIcon } from "@heroicons/react/24/solid";
4
- import { SocketContext } from '../../SocketProvider';
5
 
6
  function ChatFooter({
7
- setMessages,
8
- currentContactId,
9
  }) {
10
-
11
  const socket = useContext(SocketContext);
12
  const messageRef = useRef();
13
 
@@ -27,10 +26,8 @@ function ChatFooter({
27
  const message_bundle= {
28
  message,
29
  send_at:curr_time,
30
- send_to:currentContactId,
31
  }
32
-
33
- setMessages((prev) => [...prev, message_bundle]);
34
 
35
  if(socket){
36
  socket.emit("send_message",message_bundle);
 
1
  import React, { useContext, useEffect, useRef } from 'react'
2
  import "./ChatFooter.css";
3
  import { PaperAirplaneIcon, PhotoIcon, PaperClipIcon, FaceSmileIcon } from "@heroicons/react/24/solid";
4
+ import { SocketContext } from '../../contexts/SocketProvider';
5
 
6
  function ChatFooter({
7
+ currentChatId,
 
8
  }) {
9
+ // console.log(currentChatId)
10
  const socket = useContext(SocketContext);
11
  const messageRef = useRef();
12
 
 
26
  const message_bundle= {
27
  message,
28
  send_at:curr_time,
29
+ send_to:currentChatId,
30
  }
 
 
31
 
32
  if(socket){
33
  socket.emit("send_message",message_bundle);
client/src/components/ChatMain/ChatMain.jsx CHANGED
@@ -1,11 +1,11 @@
1
  import React, { useContext } from 'react'
2
  import Message from '../Message';
3
  import "./ChatMain.css";
4
- import { UserContext } from '../../UserProvider';
5
 
6
  const ChatMain = React.forwardRef(({
7
  messages,
8
- },ref) => {
9
 
10
  const { user } = useContext(UserContext);
11
 
@@ -16,9 +16,6 @@ const ChatMain = React.forwardRef(({
16
  }
17
 
18
  const isReceived = (message) => {
19
- // console.log("message",message.send_to);
20
- // console.log("user",user.id);
21
- // && user.id==message.from
22
  return user && message.send_to == user.id;
23
  };
24
 
 
1
  import React, { useContext } from 'react'
2
  import Message from '../Message';
3
  import "./ChatMain.css";
4
+ import { UserContext } from '../../contexts/UserProvider';
5
 
6
  const ChatMain = React.forwardRef(({
7
  messages,
8
+ }, ref) => {
9
 
10
  const { user } = useContext(UserContext);
11
 
 
16
  }
17
 
18
  const isReceived = (message) => {
 
 
 
19
  return user && message.send_to == user.id;
20
  };
21
 
client/src/components/Contacts/Contacts.jsx CHANGED
@@ -1,36 +1,62 @@
1
- import React, { useContext, useState } from 'react'
2
  import Contact from '../Contact';
3
  import "./Contacts.css";
4
- import { UserContext } from '../../UserProvider';
 
 
5
 
6
 
7
 
8
- function Contacts({
9
- allContacts,
10
- currentContact,
11
- setCurrentContact,
12
- }) {
13
 
14
  // const [activeContact, setActiveContact] = useState({});
15
- const {user} = useContext(UserContext);
 
 
 
 
 
 
 
 
16
  // handleClick
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  return (
19
  <div className='contacts'>
20
 
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
  ))
36
  }
 
1
+ import React, { useContext, useEffect, useState } from 'react'
2
  import Contact from '../Contact';
3
  import "./Contacts.css";
4
+ import { UserContext } from '../../contexts/UserProvider';
5
+ import { ChatContext } from '../../contexts/ChatProvider';
6
+ import { SocketContext } from '../../contexts/SocketProvider';
7
 
8
 
9
 
10
+ function Contacts({ }) {
 
 
 
 
11
 
12
  // const [activeContact, setActiveContact] = useState({});
13
+ const {
14
+ contacts,
15
+ setContacts,
16
+ currentChat,
17
+ setCurrentChat,
18
+ lastMessages,
19
+ } = useContext(ChatContext);
20
+ const { user } = useContext(UserContext);
21
+ const socket = useContext(SocketContext);
22
  // handleClick
23
 
24
+
25
+ useEffect(() => {
26
+ if (!socket) return;
27
+ socket.on("contact", (contact) => {
28
+ var newContacts = [...contacts, contact];
29
+
30
+ newContacts.sort((a,b)=>b.last_message.send_at - a.last_message.send_at);
31
+
32
+
33
+ setContacts(newContacts);
34
+ });
35
+
36
+ const cleanUp = () => {
37
+ if (!socket) return;
38
+ socket.off("contact");
39
+ }
40
+ return cleanUp;
41
+ }, [socket])
42
+
43
+
44
  return (
45
  <div className='contacts'>
46
 
47
 
48
  {
49
+ contacts.map((contact) => (
50
  // console.log("contact.last_message",contact,contact.last_message),
51
  // console.log(user.id),
52
  <Contact
53
  key={contact.id}
54
+ onClick={() => { setCurrentChat(contact) }}
55
  profile_pic={"logo512.png"}
56
  name={contact.username}
57
  lastmessage={contact.last_message.message}
58
  is_new={user.id == contact.last_message.send_to && contact.last_message.is_seen == 0}
59
+ isActive={currentChat.id == contact.id}
60
  />
61
  ))
62
  }
client/src/components/SideBar/SideBar.jsx CHANGED
@@ -1,36 +1,42 @@
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]);
@@ -39,7 +45,7 @@ function SideBar({
39
 
40
  <div className='side_bar'>
41
  <Search />
42
- <Contacts allContacts={contacts} currentContact={currentContact} setCurrentContact={setCurrentContact} />
43
  </div>
44
  )
45
  }
 
1
+ import React, { useContext, useEffect } from 'react'
2
  import Search from '../Search';
3
  import Contacts from '../Contacts';
4
  import "./SideBar.css";
5
+ import { SocketContext } from '../../contexts/SocketProvider';
6
+ import { ChatContext } from '../../contexts/ChatProvider';
7
 
8
 
9
+ function SideBar() {
 
 
 
 
 
10
 
11
  const socket = useContext(SocketContext);
12
 
13
+ const {
14
+ setContacts,
15
+ // setLastMessages,
16
+ } = useContext(ChatContext);
17
+
18
  useEffect(() => {
19
 
20
  const fetchData = async () => {
21
+
22
+ if (!socket) return;
23
+ socket.on("contacts", (contacts) => {
 
24
  // console.log(contacts);
25
+ var newContacts = contacts;
26
+
27
+ newContacts.sort((a,b)=>b.last_message.send_at - a.last_message.send_at);
28
+
29
+ setContacts(newContacts); // set Contacts
30
+ // setLastMessages(contacts.map((contact) => contact.last_message)); // set Last messages
31
  });
32
 
33
  socket.emit("get_contacts");
34
  }
35
+
36
  fetchData();
37
 
38
+ return () => {
39
+ if (!socket) return;
40
  socket.off("contacts");
41
  }
42
  }, [socket]);
 
45
 
46
  <div className='side_bar'>
47
  <Search />
48
+ <Contacts />
49
  </div>
50
  )
51
  }
client/src/contexts/ChatProvider.jsx ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { createContext, useState } from "react";
2
+
3
+ export const ChatContext = createContext();
4
+
5
+ export const ChatProvider = ({ children }) => {
6
+ const [contacts, setContacts] = useState([]);
7
+ const [currentChat, setCurrentChat] = useState({});
8
+ const [lastMessages, setLastMessages] = useState([]);
9
+
10
+ return (
11
+ <ChatContext.Provider value={{
12
+ contacts, setContacts,
13
+ currentChat, setCurrentChat,
14
+ lastMessages, setLastMessages,
15
+ }}>
16
+ {children}
17
+ </ChatContext.Provider>
18
+ );
19
+ }
client/src/{SocketProvider.jsx → contexts/SocketProvider.jsx} RENAMED
File without changes
client/src/{UserProvider.jsx → contexts/UserProvider.jsx} RENAMED
File without changes
server/index.ts CHANGED
@@ -352,22 +352,34 @@ io.on("connection", async (socket) => {
352
  console.log("saved message:", data.message);
353
 
354
  const sockets = await io.fetchSockets();
355
-
356
-
 
 
 
 
 
 
 
357
  sockets.forEach((client) => {
358
  if (client.data.user.id == data.send_to) {
359
  // console.log("heyy");
360
- return socket.to(client.id).emit("receive_message", {
361
- ...data,
362
- "send_to": data.send_to,
363
- "send_from": socket.data.user.id,
364
- "is_seen": 0,
365
- });
366
  }
367
  })
368
 
369
  });
370
 
 
 
 
 
 
 
 
 
 
 
371
  // upon disconnection
372
  socket.on("disconnect", (reason) => {
373
  console.log(`socket ${socket.id} disconnected due to ${reason}`);
 
352
  console.log("saved message:", data.message);
353
 
354
  const sockets = await io.fetchSockets();
355
+ const message_bundle = {
356
+ ...data,
357
+ "id":msg_id,
358
+ "send_to": data.send_to,
359
+ "send_from": socket.data.user.id,
360
+ "is_seen": 0,
361
+ };
362
+
363
+ socket.emit("receive_message",message_bundle);
364
  sockets.forEach((client) => {
365
  if (client.data.user.id == data.send_to) {
366
  // console.log("heyy");
367
+ return socket.to(client.id).emit("receive_message", message_bundle);
 
 
 
 
 
368
  }
369
  })
370
 
371
  });
372
 
373
+ socket.on("get_contact",async contact_id=>{
374
+ const contact = await db.prepare("select * from users where id = ?").get(contact_id);
375
+
376
+
377
+ socket.emit("contact",{
378
+ ...contact,
379
+ last_message: await getLastMessage({ user_id: socket.data.user.id, contact_id: contact_id }),
380
+ });
381
+ })
382
+
383
  // upon disconnection
384
  socket.on("disconnect", (reason) => {
385
  console.log(`socket ${socket.id} disconnected due to ${reason}`);