diff --git a/frontend/src/components/ScrollableChat.js b/frontend/src/components/ScrollableChat.js
new file mode 100644
index 0000000..9a21ea4
--- /dev/null
+++ b/frontend/src/components/ScrollableChat.js
@@ -0,0 +1,53 @@
+import { Avatar, Tooltip } from "@chakra-ui/react";
+import React from "react";
+import {
+ isLastMessage,
+ isSameSender,
+ isSameSenderMargin,
+ isSameUser,
+} from "../config/ChatLogics";
+import { ChatState } from "../Context/ChatProvider";
+
+const ScrollableChat = ({ messages }) => {
+ const { user } = ChatState();
+
+ return (
+
+ {messages &&
+ messages.map((m, i) => (
+
+ {(isSameSender(messages, m, i, user._id) ||
+ isLastMessage(messages, i, user._id)) && (
+
+
+
+ )}
+
+
+ {m.content}
+
+
+ ))}
+
+ );
+};
+
+export default ScrollableChat;
diff --git a/frontend/src/components/SingleChat.js b/frontend/src/components/SingleChat.js
index 6ec8323..d957327 100644
--- a/frontend/src/components/SingleChat.js
+++ b/frontend/src/components/SingleChat.js
@@ -1,14 +1,108 @@
-import { Box, IconButton, Text } from "@chakra-ui/react";
+import {
+ Box,
+ FormControl,
+ IconButton,
+ Input,
+ Spinner,
+ Text,
+ useToast,
+} from "@chakra-ui/react";
import { ArrowBackIcon } from "@chakra-ui/icons";
-import React from "react";
+import React, { useEffect, useState } from "react";
import { ChatState } from "../Context/ChatProvider";
import { getSender, getSenderFull } from "../config/ChatLogics";
import ProfileModal from "./miscellaneous/ProfileModal";
import UpdateGroupChatModal from "./miscellaneous/UpdateGroupChatModal";
+import axios from "axios";
+import "./style.css";
+import ScrollableChat from "./ScrollableChat";
const SingleChat = ({ fetchAgain, setFetchAgain }) => {
const { user, selectedChat, setSelectedChat } = ChatState();
+ const toast = useToast();
+
+ const [messages, setMessages] = useState([]);
+ const [newMessage, setNewMessage] = useState();
+ const [loading, setLoading] = useState(false);
+
+ const fetchMessages = async () => {
+ if (!selectedChat) return;
+
+ try {
+ setLoading(true);
+
+ const config = {
+ headers: {
+ Authorization: `Bearer ${user.token}`,
+ },
+ };
+
+ const { data } = await axios.get(
+ `/api/message/${selectedChat._id}`,
+ config
+ );
+ setMessages(data);
+ // console.log(data);
+ setLoading(false);
+ } catch (error) {
+ toast({
+ title: "Error Occured",
+ description: "Failed to load the messages",
+ duration: 2000,
+ status: "error",
+ isClosable: true,
+ position: "bottom",
+ });
+ setLoading(false);
+ }
+ };
+
+ useEffect(() => {
+ fetchMessages();
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [selectedChat]);
+
+ const sendMessage = async (e) => {
+ if (e.key === "Enter" && newMessage) {
+ try {
+ const config = {
+ headers: {
+ Authorization: `Bearer ${user.token}`,
+ },
+ };
+
+ setNewMessage("");
+ const { data } = await axios.post(
+ "api/message",
+ {
+ content: newMessage,
+ chatId: selectedChat._id,
+ },
+ config
+ );
+
+ // console.log(data);
+ setMessages([...messages, data]);
+ } catch (error) {
+ toast({
+ title: "Error Occured",
+ description: "Failed to send the message",
+ duration: 2000,
+ status: "error",
+ isClosable: true,
+ position: "bottom",
+ });
+ }
+ }
+ };
+
+ const typingHandler = (e) => {
+ setNewMessage(e.target.value);
+
+ // Typing indicator Logic
+ };
+
return (
<>
{selectedChat ? (
@@ -30,8 +124,12 @@ const SingleChat = ({ fetchAgain, setFetchAgain }) => {
/>
{selectedChat.isGroupChat ? (
<>
- {selectedChat.chatName}
-
+ {selectedChat.chatName}
+
>
) : (
<>
@@ -50,7 +148,30 @@ const SingleChat = ({ fetchAgain, setFetchAgain }) => {
bg="#E8E8E8"
borderRadius="lg"
overflowY="hidden"
- >
+ >
+ {loading ? (
+
+ ) : (
+
+
+
+ )}
+
+
+
+
>
) : (
{
+const UpdateGroupChatModal = ({ fetchAgain, setFetchAgain, fetchMessages }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const { user, selectedChat, setSelectedChat } = ChatState();
@@ -66,6 +66,7 @@ const UpdateGroupChatModal = ({ fetchAgain, setFetchAgain }) => {
userToRemove._id === user._id ? setSelectedChat() : setSelectedChat(data);
setFetchAgain(!fetchAgain);
+ fetchMessages()
setLoading(false);
} catch (error) {
toast({
diff --git a/frontend/src/components/style.css b/frontend/src/components/style.css
new file mode 100644
index 0000000..73d435c
--- /dev/null
+++ b/frontend/src/components/style.css
@@ -0,0 +1,7 @@
+.messages{
+ display: flex;
+ flex-direction: column;
+ overflow-y: scroll;
+ scrollbar-width: none;
+ /* background-color: #20f099b7; */
+}
\ No newline at end of file
diff --git a/frontend/src/config/ChatLogics.js b/frontend/src/config/ChatLogics.js
index 58475bc..8412d1c 100644
--- a/frontend/src/config/ChatLogics.js
+++ b/frontend/src/config/ChatLogics.js
@@ -5,3 +5,41 @@ export const getSender = (loggedUser, users) => {
export const getSenderFull = (loggedUser, users) => {
return users[0]._id === loggedUser._id ? users[1] : users[0];
};
+
+export const isSameSender = (messages, m, i, userId) => {
+ return (
+ i < messages.length - 1 &&
+ (messages[i + 1].sender._id !== m.sender._id ||
+ messages[i + 1].sender._id === undefined) &&
+ messages[i].sender._id !== userId
+ );
+};
+
+export const isLastMessage = (messages, i, userId) => {
+ return (
+ i === messages.length - 1 &&
+ messages[messages.length - 1].sender._id !== userId &&
+ messages[messages.length - 1].sender._id
+ );
+};
+
+export const isSameSenderMargin = (messages, m, i, userId) => {
+ if (
+ i < messages.length - 1 &&
+ messages[i + 1].sender._id === m.sender._id &&
+ messages[i].sender._id !== userId
+ )
+ return 33;
+ else if (
+ (i < messages.length - 1 &&
+ messages[i + 1].sender._id !== m.sender._id &&
+ messages[i].sender._id !== userId) ||
+ (i === messages.length - 1 && messages[i].sender._id !== userId)
+ )
+ return 0;
+ else return "auto";
+};
+
+export const isSameUser = (messages, m, i) => {
+ return i > 0 && messages[i - 1].sender._id === m.sender._id;
+};