Commit da4148ab authored by Balasuriya D.A.M.'s avatar Balasuriya D.A.M.

Create Group Chat Modal Part 1

parent a70b4c26
...@@ -19,4 +19,4 @@ const connectDB = async () => { ...@@ -19,4 +19,4 @@ const connectDB = async () => {
} }
}; };
module.exports = connectDB ; module.exports = connectDB ;
\ No newline at end of file
...@@ -5,10 +5,10 @@ const generateToken = (id) => { ...@@ -5,10 +5,10 @@ const generateToken = (id) => {
//add jwt secret from .env //add jwt secret from .env
return jwt.sign({ id }, process.env.JWT_SECRET, { return jwt.sign({ id }, process.env.JWT_SECRET, {
//can change the count of days as i want (secret days) //can change the count of days as i want (secret days)
expiresIn: "30d", expiresIn: "200d",
}); });
}; };
module.exports = generateToken; module.exports = generateToken;
//JWT use for pass user data to backend through JWT //JWT use for pass user data to backend through JWT
\ No newline at end of file
...@@ -172,4 +172,8 @@ const removeFromGroup = asyncHandler(async (req, res) => { ...@@ -172,4 +172,8 @@ const removeFromGroup = asyncHandler(async (req, res) => {
} }
}); });
module.exports = { accessChat, fetchChats, createGroupChat, renameGroup, addToGroup, removeFromGroup }; module.exports = { accessChat, fetchChats, createGroupChat, renameGroup, addToGroup, removeFromGroup };
\ No newline at end of file
...@@ -25,7 +25,9 @@ const registerUser = asyncHandler(async (req, res) => { ...@@ -25,7 +25,9 @@ const registerUser = asyncHandler(async (req, res) => {
password, password,
pic, pic,
}); });
//after register..also want send JWT token
//after register..also want send JWT token
if (user) { if (user) {
res.status(201).json({ res.status(201).json({
_id: user._id, _id: user._id,
...@@ -49,7 +51,7 @@ const authUser = asyncHandler(async (req, res) => { ...@@ -49,7 +51,7 @@ const authUser = asyncHandler(async (req, res) => {
const user = await User.findOne({ email }); const user = await User.findOne({ email });
//If user is already exist check it with DB data such as password //If user is already exist check it with DB data such as password
if (user && (await user.matchPassword(password))) { if (user && (await user.matchPassword(password))) {
res.json({ res.json({
_id: user._id, _id: user._id,
name: user.name, name: user.name,
...@@ -63,11 +65,13 @@ const authUser = asyncHandler(async (req, res) => { ...@@ -63,11 +65,13 @@ const authUser = asyncHandler(async (req, res) => {
} }
}); });
// /api/user?search = minosh - goint to creat search query // /api/user?search = minosh - goint to creat search query
//This is how to access the query (search query) //This is how to access the query (search query)
const allUsers = asyncHandler(async (req, res) => { const allUsers = asyncHandler(async (req, res) => {
const keyword = req.query.search const keyword = req.query.search
? { ? {
//use $or operation //use $or operation
$or: [ $or: [
//references from MongoDB pages.can get more information from that about $regex //references from MongoDB pages.can get more information from that about $regex
...@@ -79,11 +83,12 @@ const allUsers = asyncHandler(async (req, res) => { ...@@ -79,11 +83,12 @@ const allUsers = asyncHandler(async (req, res) => {
: {}; : {};
//query write to database //query write to database
const users = await User.find(keyword).find({ _id: { $ne: req.user._id } }); const users = await User.find(keyword).find({ _id: { $ne: req.user._id } });
// find({_id:{$ne:req.user._id}}) - current id user loged in // find({_id:{$ne:req.user._id}}) - current id user loged in
res.send(users); //to return res.send(users); //to return
}); });
module.exports = { registerUser, authUser,allUsers }; module.exports = { registerUser, authUser,allUsers };
\ No newline at end of file
...@@ -107,5 +107,4 @@ const chats = [ ...@@ -107,5 +107,4 @@ const chats = [
}, },
]; ];
module.exports = { chats }; module.exports = { chats };
\ No newline at end of file
...@@ -35,4 +35,4 @@ const protect = asyncHandler(async (req, res, next) => { ...@@ -35,4 +35,4 @@ const protect = asyncHandler(async (req, res, next) => {
} }
}); });
module.exports = { protect }; module.exports = { protect };
\ No newline at end of file
...@@ -15,4 +15,4 @@ const errorHandler = (err, req, res, next) => { ...@@ -15,4 +15,4 @@ const errorHandler = (err, req, res, next) => {
}); });
}; };
module.exports = { notFound, errorHandler }; module.exports = { notFound, errorHandler };
\ No newline at end of file
...@@ -15,4 +15,4 @@ const messageModel = mongoose.Schema({ ...@@ -15,4 +15,4 @@ const messageModel = mongoose.Schema({
const Message = mongoose.model("Message", messageModel); const Message = mongoose.model("Message", messageModel);
module.exports = Message; module.exports = Message;
\ No newline at end of file
const mongoose = require("mongoose"); const mongoose = require("mongoose");
const bcrypt = require("bcryptjs"); const bcrypt = require("bcryptjs");
const userSchema = mongoose.Schema({ const userSchema = mongoose.Schema({
name: { type: String, required: true }, name: { type: String, required: true },
email: { type: String, required: true,unique:true }, email: { type: String, required: true,unique:true },
...@@ -8,6 +9,7 @@ const userSchema = mongoose.Schema({ ...@@ -8,6 +9,7 @@ const userSchema = mongoose.Schema({
pic: { pic: {
type: String, type: String,
//required: true, if it is required i can use this reuired as true //required: true, if it is required i can use this reuired as true
default: default:
"https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg", "https://icon-library.com/images/anonymous-avatar-icon/anonymous-avatar-icon-25.jpg",
}, },
...@@ -31,6 +33,7 @@ userSchema.pre("save", async function (next) { ...@@ -31,6 +33,7 @@ userSchema.pre("save", async function (next) {
this.password = await bcrypt.hash(this.password, salt); //add Hash and bcrypt this.password = await bcrypt.hash(this.password, salt); //add Hash and bcrypt
}); });
const User = mongoose.model("User", userSchema); const User = mongoose.model("User", userSchema);
module.exports = User; module.exports = User;
\ No newline at end of file
...@@ -3,18 +3,16 @@ const { accessChat, fetchChats, createGroupChat, renameGroup, addToGroup, remove ...@@ -3,18 +3,16 @@ const { accessChat, fetchChats, createGroupChat, renameGroup, addToGroup, remove
const { protect } = require("../middleware/authMiddleware"); const { protect } = require("../middleware/authMiddleware");
//create router object //create router object
const router = express.Router(); const router = express.Router();
//only login user can access this route. //only login user can access this route.
router.route("/").post(protect, accessChat); //API route for one on one chat router.route("/").post(protect, accessChat);
router.route("/").get(protect, fetchChats); router.route("/").get(protect, fetchChats);
router.route("/group").post(protect, createGroupChat); //create group router.route("/group").post(protect, createGroupChat); //create group
router.route("/rename").put(protect, renameGroup); //update group router.route("/rename").put(protect, renameGroup); //update group
router.route("/groupadd").put(protect, addToGroup); //add someone to group router.route("/groupadd").put(protect, addToGroup); //add someone to group
router.route("/groupremove").put(protect, removeFromGroup); //remove from group router.route("/groupremove").put(protect, removeFromGroup); //remove from group
module.exports = router; module.exports = router;
...@@ -3,12 +3,10 @@ const { registerUser, authUser, allUsers } = require("../controllers/userControl ...@@ -3,12 +3,10 @@ const { registerUser, authUser, allUsers } = require("../controllers/userControl
const { protect } = require("../middleware/authMiddleware"); const { protect } = require("../middleware/authMiddleware");
const router = express.Router(); const router = express.Router();
router.route("/").post(registerUser).get(protect,allUsers); //User searching API end point router.route("/").post(registerUser).get(protect,allUsers); //User searching API end point
router.post("/login", authUser);
router.post("/login", authUser);
module.exports = router; module.exports = router;
const express = require("express"); const express = require("express");
const dotenv = require("dotenv"); const dotenv = require("dotenv");
const { chats } = require("./data/data"); const { chats } = require("./data/data");
...@@ -6,22 +5,22 @@ const connectDB = require("./config/db"); ...@@ -6,22 +5,22 @@ const connectDB = require("./config/db");
const colors = require("colors"); const colors = require("colors");
const userRoutes = require("./routes/userRoutes"); const userRoutes = require("./routes/userRoutes");
const chatRoutes = require("./routes/chatRoutes"); const chatRoutes = require("./routes/chatRoutes");
const { notFound,errorHandler} = require("./middleware/errorMiddleware"); const { notFound,errorHandler} = require("./middleware/errorMiddleware");
dotenv.config();
dotenv.config();
connectDB(); connectDB();
const app = express(); const app = express();
app.use(express.json()); //to accept JSON data app.use(express.json()); //to accept JSON data
app.get("/", (req, res) => { app.get("/", (req, res) => {
res.send("API is Running Successfully"); res.send("API is Running Sucessfully");
}); });
//create API end points
app.use("/api/user", userRoutes); app.use("/api/user", userRoutes);
app.use("/api/chat", chatRoutes); app.use("/api/chat", chatRoutes);
...@@ -29,6 +28,8 @@ app.use("/api/chat", chatRoutes); ...@@ -29,6 +28,8 @@ app.use("/api/chat", chatRoutes);
app.use(notFound); app.use(notFound);
app.use(errorHandler); app.use(errorHandler);
const PORT = process.env.PORT || 5000; const PORT = process.env.PORT || 5000;
app.listen(5000, console.log(`Server Started on PORT ${PORT}`.yellow.bold)); app.listen(5000, console.log(`Server Started on PORT ${PORT}`.yellow.bold));
\ No newline at end of file
...@@ -4,21 +4,19 @@ ...@@ -4,21 +4,19 @@
"private": true, "private": true,
"proxy": "http://127.0.0.1:5000", "proxy": "http://127.0.0.1:5000",
"dependencies": { "dependencies": {
"@chakra-ui/button": "^1.5.10", "@chakra-ui/icons": "^2.0.0",
"@chakra-ui/icons": "^1.1.7", "@chakra-ui/react": "^2.0.0",
"@chakra-ui/layout": "^1.8.0",
"@chakra-ui/react": "^1.8.8",
"@emotion/react": "^11.9.0", "@emotion/react": "^11.9.0",
"@emotion/styled": "^11.8.1", "@emotion/styled": "^11.8.1",
"@testing-library/jest-dom": "^5.16.3", "@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^12.1.4", "@testing-library/react": "^13.2.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^13.5.0",
"axios": "^0.26.1", "axios": "^0.27.2",
"framer-motion": "^6.2.10", "framer-motion": "^4.1.17",
"react": "^18.0.0", "react": "^18.1.0",
"react-dom": "^18.0.0", "react-dom": "^18.1.0",
"react-router-dom": "^5.3.0", "react-router-dom": "^5.3.1",
"react-scripts": "5.0.0", "react-scripts": "5.0.1",
"web-vitals": "^2.1.4" "web-vitals": "^2.1.4"
}, },
"scripts": { "scripts": {
......
...@@ -15,11 +15,14 @@ ...@@ -15,11 +15,14 @@
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<link rel="stylesheet" <link
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css" rel="stylesheet"
integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w==" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
crossorigin="anonymous" integrity="sha512-iBBXm8fW90+nuLcSKlbmrPcLa0OT92xO1BIsZ+ywDWZCvqsWgccV3gFoRBv0z+8dLJgyAHIhR35VZc2oM/gI1w=="
referrerpolicy="no-referrer" /> crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
......
@import url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@300&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Work+Sans:wght@300&display=swap');
.App{ .App {
min-height: 100vh; min-height: 100vh;
display: flex; display: flex;
background-image: url("./background.jpg"); background-image: url("./background.jpg");
background-size: cover; background-size: cover;
background-position: center; background-position: center;
color:black; color: black;
} }
\ No newline at end of file
import "./App.css"; import "./App.css";
import { Route } from "react-router-dom"; import { Route } from "react-router-dom";
import Homepage from "./Pages/Homepage"; import Homepage from "./Pages/Homepage";
import ChatPage from "./Pages/ChatPage"; import ChatPage from "./Pages/ChatPage";
function App() { function App() {
return ( return (
<div className="App"> <div className="App">
<Route path="/" component={Homepage} exact /> <Route path="/" component={Homepage } exact />
<Route path="/chats" component={ChatPage} /> <Route path="/chats" component={ChatPage } />
</div> </div>
); );
......
...@@ -22,8 +22,7 @@ const ChatProvider = ({ children }) => { ...@@ -22,8 +22,7 @@ const ChatProvider = ({ children }) => {
}, [history]); }, [history]);
return ( return (
<ChatContext.Provider value={{ user, setUser, selectedChat, setSelectedChat, chats, setChats }} <ChatContext.Provider value={{ user, setUser, selectedChat, setSelectedChat, chats, setChats }}>
>
{children} {children}
</ChatContext.Provider> </ChatContext.Provider>
); );
......
//import React from "react";
import { Box } from "@chakra-ui/react"; import { Box } from "@chakra-ui/react";
import { ChatState } from "../Context/ChatProvider"; import { ChatState } from "../Context/ChatProvider";
import SideDrawer from "../components/miscellaneous/SideDrawer"; import SideDrawer from "../components/miscellaneous/SideDrawer";
import MyChats from "../components/MyChats"; import MyChats from "../components/MyChats";
import ChatBox from "../components/ChatBox"; import ChatBox from "../components/ChatBox";
const ChatPage = () => { const ChatPage = () => {
const { user } = ChatState(); const { user } = ChatState();
return ( return (
<div style={{ width: "100%" }}> <div style={{ width: "100%" }}>
{user && <SideDrawer/>} {user && <SideDrawer />}
<Box <Box
d="flex" display="flex"
justifyContent="space-between" justifyContent="space-between"
w="100%" width="100%"
h="91.5vh" height="91.5vh"
p="10px" padding="10px"
> >
{user && <MyChats />}
{user && <MyChats/>} {user && <ChatBox />}
{user && <ChatBox/>}
</Box>
</Box>
</div> </div>
); );
}; };
export default ChatPage; export default ChatPage;
\ No newline at end of file
...@@ -14,6 +14,8 @@ import Login from "../components/Authentication/Login"; ...@@ -14,6 +14,8 @@ import Login from "../components/Authentication/Login";
import Signup from "../components/Authentication/Signup"; import Signup from "../components/Authentication/Signup";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
const Homepage = () => { const Homepage = () => {
const history = useHistory(); const history = useHistory();
...@@ -21,12 +23,13 @@ const Homepage = () => { ...@@ -21,12 +23,13 @@ const Homepage = () => {
useEffect(() => { useEffect(() => {
const user = JSON.parse(localStorage.getItem("userInfo")); const user = JSON.parse(localStorage.getItem("userInfo"));
//check if user is loged in push back to the chat page //check if user is loged in
if (user) history.push("/chats"); if (user) history.push("/chats");
}, [history]); }, [history]);
return ( return (
//use container from chakra ui and remove div //use container from chakra ui and remove div
<Container maxW="xl" centerContent> <Container maxW="xl" centerContent>
...@@ -66,8 +69,10 @@ const Homepage = () => { ...@@ -66,8 +69,10 @@ const Homepage = () => {
</TabPanels> </TabPanels>
</Tabs> </Tabs>
</Box> </Box>
</Container> </Container>
); );
}; };
export default Homepage; export default Homepage;
\ No newline at end of file
...@@ -9,18 +9,22 @@ import { useToast } from "@chakra-ui/react"; ...@@ -9,18 +9,22 @@ import { useToast } from "@chakra-ui/react";
import axios from "axios"; import axios from "axios";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
const Login = () => { const Login = () => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [email, setEmail] = useState(); const [email, setEmail] = useState();
const [password, setPassword] = useState(); const [password, setPassword] = useState();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const toast = useToast(); const toast = useToast();
const history = useHistory(); const history = useHistory();
const handleClick = () => setShow(!show); const handleClick = () => setShow(!show);
const submitHandler =async() => { const submitHandler =async() => {
setLoading(true); setLoading(true);
if (!email || !password) { if (!email || !password) {
toast({ toast({
...@@ -77,6 +81,8 @@ const Login = () => { ...@@ -77,6 +81,8 @@ const Login = () => {
} }
}; };
return ( return (
//Use vstack to allign verticaly //Use vstack to allign verticaly
<VStack spacing="5px" color="black"> <VStack spacing="5px" color="black">
...@@ -84,8 +90,9 @@ const Login = () => { ...@@ -84,8 +90,9 @@ const Login = () => {
<FormControl id="email" isRequired> <FormControl id="email" isRequired>
<FormLabel>Email</FormLabel> <FormLabel>Email</FormLabel>
<Input <Input
value={email} value={email}
placeholder="Enter Your Email" placeholder="Enter Your Email"
onChange={(e)=>setEmail(e.target.value)} onChange={(e)=>setEmail(e.target.value)}
...@@ -100,7 +107,7 @@ const Login = () => { ...@@ -100,7 +107,7 @@ const Login = () => {
<Input <Input
type={show?"text":"password"} type={show?"text":"password"}
placeholder="Enter Your Password" placeholder="Enter Your Password"
value={password} value={password}
onChange={(e)=>setPassword(e.target.value)} onChange={(e)=>setPassword(e.target.value)}
/> />
...@@ -120,6 +127,7 @@ const Login = () => { ...@@ -120,6 +127,7 @@ const Login = () => {
style={{ marginTop: 15 }} style={{ marginTop: 15 }}
onClick={submitHandler} onClick={submitHandler}
isLoading={loading} isLoading={loading}
> >
Login Login
...@@ -137,7 +145,8 @@ const Login = () => { ...@@ -137,7 +145,8 @@ const Login = () => {
</Button> </Button>
</VStack> </VStack>
); );
} }
export default Login; export default Login;
\ No newline at end of file
...@@ -9,9 +9,11 @@ import { useToast } from "@chakra-ui/react"; ...@@ -9,9 +9,11 @@ import { useToast } from "@chakra-ui/react";
import axios from "axios"; import axios from "axios";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
const Signup = () => { const Signup = () => {
const [show, setShow] = useState(false); const [show, setShow] = useState(false);
const [name, setName] = useState(); const [name, setName] = useState();
const [email, setEmail] = useState(); const [email, setEmail] = useState();
const [confirmpassword, setConfirmpassword] = useState(); const [confirmpassword, setConfirmpassword] = useState();
...@@ -21,6 +23,7 @@ const Signup = () => { ...@@ -21,6 +23,7 @@ const Signup = () => {
const toast = useToast(); const toast = useToast();
const history = useHistory(); const history = useHistory();
const handleClick = () => setShow(!show); const handleClick = () => setShow(!show);
const postDetails = (pics) => { const postDetails = (pics) => {
...@@ -133,10 +136,14 @@ const Signup = () => { ...@@ -133,10 +136,14 @@ const Signup = () => {
}); });
setLoading(false); setLoading(false);
} }
}; };
return (
//Use vstack to allign verticaly
return (
//Use vstack to allign verticaly
<VStack spacing="5px" color="black"> <VStack spacing="5px" color="black">
<FormControl id="first-name" isRequired> <FormControl id="first-name" isRequired>
<FormLabel>Name</FormLabel> <FormLabel>Name</FormLabel>
...@@ -220,7 +227,8 @@ const Signup = () => { ...@@ -220,7 +227,8 @@ const Signup = () => {
</VStack> </VStack>
); );
} }
export default Signup; export default Signup;
\ No newline at end of file
...@@ -6,4 +6,4 @@ const ChatBox = () => { ...@@ -6,4 +6,4 @@ const ChatBox = () => {
); );
}; };
export default ChatBox; export default ChatBox;
\ No newline at end of file
import { Stack } from "@chakra-ui/layout"; import { Stack, Skeleton } from "@chakra-ui/react";
import { Skeleton } from "@chakra-ui/react";
import React from "react"; import React from "react";
const ChatLoading = () => { const ChatLoading = () => {
return ( return (
<Stack> <Stack>
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
<Skeleton height="45px" /> <Skeleton height='40px' />
</Stack> </Stack>
); );
}; };
export default ChatLoading; export default ChatLoading
\ No newline at end of file \ No newline at end of file
import { useToast } from "@chakra-ui/react"; import { AddIcon } from "@chakra-ui/icons";
import { Box, Button, Stack, useToast, Text } from "@chakra-ui/react";
import axios from "axios"; import axios from "axios";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { ChatState } from "../Context/ChatProvider"; import { ChatState } from "../Context/ChatProvider";
import { Box, Stack, Text } from "@chakra-ui/layout";
import { Button } from "@chakra-ui/button";
import { AddIcon } from "@chakra-ui/icons";
import ChatLoading from "./ChatLoading"; import ChatLoading from "./ChatLoading";
import { getSender } from "../config/ChatLogics"; import { getSender } from "../config/ChatLogics";
import GroupChatModal from "./miscellaneous/GroupChatModal";
const MyChats = () => { const MyChats = () => {
const [loggedUser, setLoggedUser] = useState(); const [loggedUser, setLoggedUser] = useState();
const { selectedChat, setSelectedChat, user, chats, setChats } = ChatState(); const { user, selectedChat, setSelectedChat, chats, setChats } = ChatState();
const toast = useToast(); const toast = useToast();
...@@ -22,11 +20,13 @@ const MyChats = () => { ...@@ -22,11 +20,13 @@ const MyChats = () => {
const config = { const config = {
headers: { headers: {
Authorization: `Bearer ${user.token}`, Authorization: `Bearer ${user.token}`,
}, },
}; };
const { data } = await axios.get("/api/chat", config); const { data } = await axios.get("/api/chat", config);
console.log(data); console.log(data);
setChats(data); //setting all of the chats setChats(data);
} catch (error) { } catch (error) {
toast({ toast({
title: "Error Occured!", title: "Error Occured!",
...@@ -35,7 +35,6 @@ const MyChats = () => { ...@@ -35,7 +35,6 @@ const MyChats = () => {
duration: 5000, duration: 5000,
isClosable: true, isClosable: true,
position: "bottom-left", position: "bottom-left",
}); });
} }
}; };
...@@ -43,11 +42,11 @@ const MyChats = () => { ...@@ -43,11 +42,11 @@ const MyChats = () => {
useEffect(() => { useEffect(() => {
setLoggedUser(JSON.parse(localStorage.getItem("userInfo"))); setLoggedUser(JSON.parse(localStorage.getItem("userInfo")));
fetchChats(); fetchChats();
}, []); },[])
return ( return (
<Box <Box
d={{ base: selectedChat ? "none" : "flex", md: "flex" }} display={{ base: selectedChat ? "none" : "flex", md: "flex" }}
flexDir="column" flexDir="column"
alignItems="center" alignItems="center"
p={3} p={3}
...@@ -61,23 +60,25 @@ const MyChats = () => { ...@@ -61,23 +60,25 @@ const MyChats = () => {
px={3} px={3}
fontSize={{ base: "28px", md: "30px" }} fontSize={{ base: "28px", md: "30px" }}
fontFamily="Work sans" fontFamily="Work sans"
d="flex" display="flex"
w="100%" w="100%"
justifyContent="space-between" justifyContent="space-between"
alignItems="center" alignItems="center"
> >
My Chats My Chats
<GroupChatModal>
<Button <Button
d="flex" display="flex"
fontSize={{ base: "17px", md: "10px", lg: "17px" }} fontSize={{ base: "17px", md: "10px", lg: "17px" }}
rightIcon={<AddIcon/>} rightIcon={<AddIcon/>}
> >
New Organization Chat New Organization Chat
</Button>
</Button> </GroupChatModal>
</Box> </Box>
<Box <Box
d="flex" display="flex"
flexDir="column" flexDir="column"
p={3} p={3}
bg="#F8F8F8" bg="#F8F8F8"
...@@ -100,21 +101,19 @@ const MyChats = () => { ...@@ -100,21 +101,19 @@ const MyChats = () => {
key={chat._id} key={chat._id}
> >
<Text> <Text>
{!chat.isGroupChat {!chat.isGoupChat ? getSender (loggedUser, chat.users):chat.chatName}
? getSender(loggedUser, chat.users)
: chat.chatName}
</Text> </Text>
</Box> </Box>
))} ))}
</Stack> </Stack>
): ( ): (
<ChatLoading/> <ChatLoading/>
)} )}
</Box>
</Box>
</Box> </Box>
); );
}; };
export default MyChats; export default MyChats;
\ No newline at end of file
import { Box, Text } from "@chakra-ui/layout"; import { Avatar, Box, Text } from "@chakra-ui/react";
import { Avatar } from "@chakra-ui/react";
import React from "react"; import React from "react";
import { ChatState } from "../../Context/ChatProvider";
const UserListItem = ({ user, handleFunction }) => {
const UserListItem = ({user, handleFunction }) => {
return ( return (
<Box <Box
onClick={handleFunction} onClick={handleFunction}
cursor="pointer" cursor="pointer"
bg="#E8E8E8" bg="#E8E8E8"
_hover={{ _hover={{
background: "#38BAC", background: "#38B2AC",
color:"white", color:"white",
}} }}
w="100%" w="100%"
d="flex"
alignItems="center" alignItems="center"
color="black" color="black"
px={3} px={3}
...@@ -32,7 +29,6 @@ const UserListItem = ({user, handleFunction }) => { ...@@ -32,7 +29,6 @@ const UserListItem = ({user, handleFunction }) => {
cursor="pointer" cursor="pointer"
name={user.name} name={user.name}
src={user.pic} src={user.pic}
/> />
<Box> <Box>
<Text>{user.name}</Text> <Text>{user.name}</Text>
...@@ -47,4 +43,4 @@ const UserListItem = ({user, handleFunction }) => { ...@@ -47,4 +43,4 @@ const UserListItem = ({user, handleFunction }) => {
); );
}; };
export default UserListItem; export default UserListItem
\ No newline at end of file \ No newline at end of file
import React, { useState } from "react";
import { useDisclosure, Modal, ModalBody, ModalCloseButton, ModalContent, ModalFooter, ModalHeader, ModalOverlay, Button, useToast, FormControl, Input } from "@chakra-ui/react";
import { ChatState } from "../../Context/ChatProvider";
import axios from "axios";
import UserListItem from "../UserAvatar/UserListItem";
const GroupChatModal = ({ children }) => {
const { isOpen, onOpen, onClose } = useDisclosure();
const [groupChatName, setGroupChatName] = useState();
const [selectedUsers, setSelectedUsers] = useState([]);
const [search, setSearch] = useState("");
const [searchResult, setSearchResult] = useState([]);
const [loading, setLoading] = useState(false);
const toast = useToast();
const { user, chats, setChats } = ChatState();
const handleSearch = async(query) => {
setSearch(query);
if(!query){
return;
}
try {
setLoading(true);
const config = {
headers: {
Authorization:`Bearer ${user.token}`,
},
};
const { data } = await axios.get(`/api/user?search=${search}`, config);
console.log(data);
setLoading(false);
setSearchResult(data);
} catch (error) {
toast({
title: "Error Occured!",
description: "Failed to Load the Search Result",
status: "error",
duration: 5000,
isClosable: true,
position:"bottom-left",
});
}
};
const handleSubmit = () => { };
const handleGroup = () => { };
return (
<>
<span onClick={onOpen}>{children}</span>
<Modal isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader
fontSize="35px"
fontFamily="Work sans"
display="flex"
justifyContent="center"
>
Create Organization Chat
</ModalHeader>
<ModalCloseButton />
<ModalBody display="flex" flexDir="column" alignItems="center">
<FormControl>
<Input
placeholder="Organization Name"
marginBottom={3}
onChange={(e) => setGroupChatName(e.target.value)}
/>
</FormControl>
<FormControl>
<Input
placeholder="Add Users eg:Doctors,Mining Engineers,Emergency Units"
marginBottom={1}
onChange={(e) => handleSearch(e.target.value)}
/>
</FormControl>
{/* selected users */}
{loading ? (
<div>loading</div>
) : (
searchResult
?.slice(0, 4)
.map((user) => (
<UserListItem
key={user._id}
user={user}
handleFunction={() => handleGroup(user)}
/>
))
)}
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" onClick={handleSubmit}>
Create Organization
</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
};
export default GroupChatModal;
\ No newline at end of file
import { ViewIcon } from "@chakra-ui/icons";
import { useDisclosure } from "@chakra-ui/react";
import React from "react"; import React from "react";
import { IconButton } from "@chakra-ui/button"; import { ViewIcon } from "@chakra-ui/icons";
import { Modal } from "@chakra-ui/react"; import { useDisclosure,IconButton,Modal,ModalOverlay,ModalContent,ModalHeader,ModalCloseButton,ModalBody,Button,ModalFooter,Image, Text } from "@chakra-ui/react";
import { ModalOverlay } from "@chakra-ui/react";
import { ModalContent } from "@chakra-ui/react";
import { ModalHeader } from "@chakra-ui/react";
import { ModalCloseButton } from "@chakra-ui/react";
import { ModalBody } from "@chakra-ui/react";
import { Button } from "@chakra-ui/button";
import { ModalFooter } from "@chakra-ui/react";
import { Image, Text } from "@chakra-ui/react";
...@@ -72,4 +64,4 @@ const ProfileModal = ({user, children}) => { ...@@ -72,4 +64,4 @@ const ProfileModal = ({user, children}) => {
); );
}; };
export default ProfileModal; export default ProfileModal;
\ No newline at end of file
import { //import React from "react";
Tooltip,
Menu, import { Tooltip, Menu, MenuButton, MenuList, Avatar, MenuItem, MenuDivider, Box, Text, Button, Drawer, useDisclosure, DrawerOverlay, DrawerContent, DrawerHeader, DrawerBody, Input, useToast, Spinner } from "@chakra-ui/react";
MenuButton,
MenuList,
Avatar,
MenuItem,
MenuDivider,
Drawer,
useDisclosure,
DrawerOverlay,
DrawerContent,
DrawerHeader,
DrawerBody,
Input,
useToast,
Spinner,
} from "@chakra-ui/react";
import React, { useState } from "react"; import React, { useState } from "react";
import { BellIcon, ChevronDownIcon } from "@chakra-ui/icons"; import { BellIcon, ChevronDownIcon } from "@chakra-ui/icons";
import { Box, Text } from "@chakra-ui/layout";
import { Button } from "@chakra-ui/button";
import { ChatState } from "../../Context/ChatProvider"; import { ChatState } from "../../Context/ChatProvider";
import ProfileModal from "./ProfileModal"; import ProfileModal from "./ProfileModal";
import { useHistory } from "react-router-dom"; import { useHistory } from "react-router-dom";
import axios from "axios";
import ChatLoading from "../ChatLoading"; import ChatLoading from "../ChatLoading";
import axios from "axios";
import UserListItem from "../UserAvatar/UserListItem"; import UserListItem from "../UserAvatar/UserListItem";
const SideDrawer = () => { const SideDrawer = () => {
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const [searchResult, setSearchResult] = useState([]); const [searchResult, setSearchResult] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [loadingChat, setLoadingChat] = useState(); const [loadingChat, setLoadingChat] = useState();
const { user, setSelectedChat,chats,setChats } = ChatState(); const { user, setSelectedChat, chats, setChats } = ChatState();
const history = useHistory(); const history = useHistory();
const { isOpen, onOpen, onClose } = useDisclosure(); const { isOpen, onOpen, onClose } = useDisclosure();
const logoutHandler = () => { const logoutHandler = () => {
localStorage.removeItem("userInfo"); localStorage.removeItem("userInfo");
history.push("/"); history.push("/");
}; };
const toast = useToast(); const toast = useToast();
const handleSearch = async () => { const handleSearch = async() => {
if (!search) { if (!search) {
toast({ toast({
title: "Please Enter something in search", title: "Please Enter something in search",
...@@ -59,7 +43,7 @@ const SideDrawer = () => { ...@@ -59,7 +43,7 @@ const SideDrawer = () => {
} }
try { try {
setLoading(true) setLoading(true);
const config = { const config = {
headers: { headers: {
...@@ -68,7 +52,7 @@ const SideDrawer = () => { ...@@ -68,7 +52,7 @@ const SideDrawer = () => {
}; };
const { data } = await axios.get(`/api/user?search=${search}`, config); const { data } = await axios.get(`/api/user?search=${search}`, config);
setLoading(false); setLoading(false);
setSearchResult(data); setSearchResult(data);
} catch (error) { } catch (error) {
...@@ -82,20 +66,21 @@ const SideDrawer = () => { ...@@ -82,20 +66,21 @@ const SideDrawer = () => {
}); });
} }
}; };
const accessChat = async (userId) => { const accessChat = async(userId) => {
try { try {
setLoadingChat(true); setLoadingChat(true);
const config = { const config = {
headers: { headers: {
"Content-type": "application/json", "Content-type":"application/json",
Authorization: `Bearer ${user.token}`, Authorization: `Bearer ${user.token}`,
}, },
}; };
const { data } = await axios.post("/api/chat", { userId }, config); const { data } = await axios.post("/api/chat", { userId }, config);
if (!chats.find((c) => c._id === data._id)) setChats([data, ...chats]); //normal find function in java scripts //normal find function in java script
if (!chats.find((c) => c._id === data._id)) setChats([data, ...chats]);
setSelectedChat(data); setSelectedChat(data);
setLoadingChat(false); setLoadingChat(false);
...@@ -105,30 +90,26 @@ const SideDrawer = () => { ...@@ -105,30 +90,26 @@ const SideDrawer = () => {
title: "Error fetching the chat", title: "Error fetching the chat",
description: error.message, description: error.message,
status: "error", status: "error",
duration: 5000, duration: "5000",
isClosable: true, isClosable: true,
position: "bottom-left", position: "bottom-left",
}); });
} }
}; };
return ( return (
<> <>
<Box <Box
d="flex" display="flex"
justifyContent="space-between" justifyContent="space-between"
alignItems="center" alignItems="center"
bg="white" bgColor="white"
w="100%" width="100%"
p="5px 10px 5px 10px" padding="5px 10px 5px 10px"
borderWidth="5px" borderWidth="5px"
> >
<Tooltip <Tooltip label="Search User to chat" hasArrow placement="bottom-end">
label="Search User to chat"
hasArrow
placement="bottom-end"
>
<Button variant="ghost" onClick={onOpen}> <Button variant="ghost" onClick={onOpen}>
<i class="fas fa-search"></i> <i class="fas fa-search"></i>
<Text d={{base:"none",md:"flex"}} px="4"> <Text d={{base:"none",md:"flex"}} px="4">
...@@ -174,19 +155,17 @@ const SideDrawer = () => { ...@@ -174,19 +155,17 @@ const SideDrawer = () => {
<DrawerOverlay /> <DrawerOverlay />
<DrawerContent> <DrawerContent>
<DrawerHeader borderBottomWidth="1px">Search User</DrawerHeader> <DrawerHeader borderBottomWidth="1px">Search User</DrawerHeader>
<DrawerBody> <DrawerBody>
<Box d="flex" pb={2}> <Box display="flex" paddingBottom={2}>
<Input <Input
placeholder="Search by name or email" placeholder="Search by name or email"
mr={2} margin={2}
value={search} value={search}
onChange={(e) => setSearch(e.target.value)} onChange={(e) => setSearch(e.target.value)}
/> />
<Button <Button
onClick={handleSearch} onClick={handleSearch}
> >Go</Button>
Go
</Button>
</Box> </Box>
{loading ? <ChatLoading /> : {loading ? <ChatLoading /> :
( (
...@@ -199,13 +178,14 @@ const SideDrawer = () => { ...@@ -199,13 +178,14 @@ const SideDrawer = () => {
)) ))
) )
} }
{loadingChat && <Spinner ml="auto" d="flex" />} {loadingChat && <Spinner ml="auto" display="flex" />}
</DrawerBody> </DrawerBody>
</DrawerContent> </DrawerContent>
</Drawer> </Drawer>
</> </>
); );
}; };
export default SideDrawer; export default SideDrawer;
\ No newline at end of file
export const getSender = (loggedUser, users) => { export const getSender = (loggedUser, users) => {
//if it is not a organization chat nelow logic will helpfull
return users[0]._id === loggedUser._id ? users[1].name : users[0].name; return users[0]._id === loggedUser._id ? users[1].name : users[0].name;
}; };
\ No newline at end of file
...@@ -7,15 +7,19 @@ import { BrowserRouter } from "react-router-dom"; ...@@ -7,15 +7,19 @@ import { BrowserRouter } from "react-router-dom";
import ChatProvider from "./Context/ChatProvider"; import ChatProvider from "./Context/ChatProvider";
ReactDOM.render( ReactDOM.render(
<ChatProvider> <ChatProvider>
<BrowserRouter> <BrowserRouter>
<ChakraProvider> <ChakraProvider>
<App /> <App />
</ChakraProvider> </ChakraProvider>
</BrowserRouter> </BrowserRouter>
</ChatProvider>, </ChatProvider>,
document.getElementById("root") document.getElementById("root")
//rendering everything on root tag
); );
{ {
"name": "tele-medicine", "name": "miner-doc",
"version": "1.0.0", "version": "1.0.0",
"description": "", "description": "",
"main": "server.js", "main": "server.js",
...@@ -9,8 +9,13 @@ ...@@ -9,8 +9,13 @@
"author": "Minosh Balasuriya", "author": "Minosh Balasuriya",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"dotenv": "^16.0.0", "bcryptjs": "^2.4.3",
"express": "^4.17.3", "colors": "^1.4.0",
"nodemon": "^2.0.15" "dotenv": "^16.0.1",
"express": "^4.18.1",
"express-async-handler": "^1.2.0",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.3.3",
"nodemon": "^2.0.16"
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment