├── src
├── index.css
├── Assets
│ └── login.png
├── setupTests.js
├── App.test.js
├── reportWebVitals.js
├── index.js
├── Firebase
│ └── Firebase.js
├── App.css
├── Components
│ ├── SignUp.js
│ ├── DeleteModal.js
│ ├── CreateRoom.js
│ ├── EditProfile.js
│ ├── Home.js
│ ├── Rooms.js
│ ├── FileUpload.js
│ ├── Chat.js
│ ├── Application.js
│ └── Messages.js
└── App.js
├── .firebaserc
├── Assets
└── chatify.png
├── public
├── favicon.ico
├── logo192.png
├── logo512.png
├── robots.txt
├── manifest.json
└── index.html
├── firebase.json
├── .gitignore
├── package.json
└── README.md
/src/index.css:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.firebaserc:
--------------------------------------------------------------------------------
1 | {
2 | "projects": {
3 | "default": "chatify-49"
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/Assets/chatify.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoldStar0103/Chatify/HEAD/Assets/chatify.png
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoldStar0103/Chatify/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoldStar0103/Chatify/HEAD/public/logo192.png
--------------------------------------------------------------------------------
/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoldStar0103/Chatify/HEAD/public/logo512.png
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/src/Assets/login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoldStar0103/Chatify/HEAD/src/Assets/login.png
--------------------------------------------------------------------------------
/firebase.json:
--------------------------------------------------------------------------------
1 | {
2 | "hosting": {
3 | "public": "build",
4 | "ignore": [
5 | "firebase.json",
6 | "**/.*",
7 | "**/node_modules/**"
8 | ]
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom';
6 |
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import App from './App';
3 |
4 | test('renders learn react link', () => {
5 | render();
6 | const linkElement = screen.getByText(/learn react/i);
7 | expect(linkElement).toBeInTheDocument();
8 | });
9 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
25 | .firebase
--------------------------------------------------------------------------------
/src/reportWebVitals.js:
--------------------------------------------------------------------------------
1 | const reportWebVitals = onPerfEntry => {
2 | if (onPerfEntry && onPerfEntry instanceof Function) {
3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
4 | getCLS(onPerfEntry);
5 | getFID(onPerfEntry);
6 | getFCP(onPerfEntry);
7 | getLCP(onPerfEntry);
8 | getTTFB(onPerfEntry);
9 | });
10 | }
11 | };
12 |
13 | export default reportWebVitals;
14 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import './index.css';
4 | import App from './App';
5 | import reportWebVitals from './reportWebVitals';
6 |
7 | ReactDOM.render(
8 |
9 |
10 | ,
11 | document.getElementById('root')
12 | );
13 |
14 | // If you want to start measuring performance in your app, pass a function
15 | // to log results (for example: reportWebVitals(console.log))
16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
17 | reportWebVitals();
18 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "standalone",
23 | "theme_color": "#000000",
24 | "background_color": "#ffffff"
25 | }
26 |
--------------------------------------------------------------------------------
/src/Firebase/Firebase.js:
--------------------------------------------------------------------------------
1 | import firebase from "firebase/app";
2 | import "firebase/auth";
3 | import "firebase/firestore";
4 | import "firebase/storage";
5 |
6 | const provider = new firebase.auth.GoogleAuthProvider();
7 |
8 | const firebaseConfig = {
9 | apiKey: "AIzaSyDoN-nSGUo_1h87nkOXSXX2vv4IBXBXey0",
10 | authDomain: "chatify-49.firebaseapp.com",
11 | projectId: "chatify-49",
12 | storageBucket: "chatify-49.appspot.com",
13 | messagingSenderId: "1034185885241",
14 | appId: "1:1034185885241:web:a46af138b7a40d318defe8",
15 | measurementId: "G-EHQ2YBVYY9",
16 | };
17 |
18 | const firebaseApp = firebase.initializeApp(firebaseConfig);
19 |
20 | const db = firebaseApp.firestore();
21 | const auth = firebase.auth();
22 | const storage = firebase.storage();
23 |
24 | export { db, auth, provider, storage };
25 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "chatify",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.11.3",
7 | "@material-ui/icons": "^4.11.2",
8 | "@testing-library/jest-dom": "^5.11.10",
9 | "@testing-library/react": "^11.2.6",
10 | "@testing-library/user-event": "^12.8.3",
11 | "emoji-mart": "^3.0.1",
12 | "firebase": "^8.4.1",
13 | "react": "^17.0.2",
14 | "react-anchorme": "^2.2.0",
15 | "react-dom": "^17.0.2",
16 | "react-icons": "^4.2.0",
17 | "react-router-dom": "^5.2.0",
18 | "react-scripts": "4.0.3",
19 | "react-scrollable-feed": "^1.3.0",
20 | "web-vitals": "^1.1.1"
21 | },
22 | "scripts": {
23 | "start": "react-scripts start",
24 | "build": "react-scripts build",
25 | "test": "react-scripts test",
26 | "eject": "react-scripts eject"
27 | },
28 | "eslintConfig": {
29 | "extends": [
30 | "react-app",
31 | "react-app/jest"
32 | ]
33 | },
34 | "browserslist": {
35 | "production": [
36 | ">0.2%",
37 | "not dead",
38 | "not op_mini all"
39 | ],
40 | "development": [
41 | "last 1 chrome version",
42 | "last 1 firefox version",
43 | "last 1 safari version"
44 | ]
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Chatify
4 |
5 | ### Personal Chat Room or Workspace to share resources and hangout with friends.
6 |
7 | ### https://chatifynew.vercel.app/
8 |
9 |
10 |

11 |
12 |
13 |
14 |
15 | ## Build With
16 |
17 | - `React.js`
18 | - `Firebase`
19 | - `Material UI`
20 | - `React Icons`
21 |
22 | ## Features:
23 |
24 | - Easy SignIn with Google
25 | - Create Rooms
26 | - Realtime group messaging with image sharing
27 | - Supports Emoji
28 | - Reaction on messages
29 |
30 | ## Installation and Usage
31 |
32 | ### Clone this repository
33 |
34 | `git clone https://github.com/soumyajit4419/Chatify.git`
35 | `cd chatify`
36 |
37 | ### Install Dependencies
38 |
39 | `npm install`
40 |
41 | In the project directory, you can run:
42 |
43 | ### npm start
44 |
45 | Runs the app in the development mode.\
46 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
47 |
48 | The page will reload if you make edits.\
49 | You will also see any lint errors in the console.
50 |
51 | ### npm run build
52 |
53 | Builds the app for production to the `build` folder.\
54 | It correctly bundles React in production mode and optimizes the build for the best performance.
55 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | body {
2 | height: 100vh !important;
3 | overflow: hidden !important;
4 | background-color: #22273b !important;
5 | }
6 |
7 | /* width */
8 | ::-webkit-scrollbar {
9 | width: 9px;
10 | }
11 |
12 | /* Track */
13 | ::-webkit-scrollbar-track {
14 | background: #22273b !important;
15 | border-radius: 5px;
16 | }
17 |
18 | /* Handle */
19 | ::-webkit-scrollbar-thumb {
20 | background: #151b2d !important;
21 | border-radius: 5px;
22 | }
23 |
24 | .emoji-mart {
25 | position: absolute !important;
26 | bottom: 70px !important;
27 | }
28 |
29 | .emoji-mart-preview {
30 | display: none !important;
31 | }
32 |
33 | .MuiInputLabel-outlined {
34 | color: rgba(173, 173, 173, 0.89) !important;
35 | }
36 |
37 | .MuiOutlinedInput-notchedOutline {
38 | border: 0 !important;
39 | }
40 |
41 | .MuiInputBase-root {
42 | color: rgb(245, 245, 245) !important;
43 | }
44 |
45 | .MuiInputBase-root.Mui-disabled {
46 | color: rgb(255 255 255 / 53%) !important;
47 | cursor: default !important;
48 | }
49 |
50 | .MuiDivider-root {
51 | background-color: rgb(0 0 0 / 40%) !important;
52 | }
53 |
54 | .MuiDialog-paper {
55 | overflow-y: visible !important;
56 | background-color: #202035 !important;
57 | color: #dcddde !important;
58 | width: 530px;
59 | }
60 |
61 | .emoji-mart-dark {
62 | color: #fff;
63 | border-color: #22273b !important;
64 | background-color: #121628 !important;
65 | }
66 |
67 | .emoji-mart-dark .emoji-mart-category-label span {
68 | background-color: #121628 !important;
69 | color: #fff;
70 | border-radius: 5px;
71 | }
72 |
73 | .emoji-mart-dark .emoji-mart-search input {
74 | color: #fff;
75 | border-color: #22273b;
76 | background-color: #22273b;
77 | }
78 |
79 | a {
80 | color: #e3a7ff;
81 | }
82 |
83 | .MuiSnackbarContent-root {
84 | background-color: rgb(109 52 125) !important;
85 | }
86 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | Chatify
28 |
29 |
30 |
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/Components/SignUp.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Button from "@material-ui/core/Button";
3 | import { FcGoogle } from "react-icons/fc";
4 | import { makeStyles } from "@material-ui/core/styles";
5 | import Container from "@material-ui/core/Container";
6 | import loginImg from "../Assets/login.png";
7 | import Topography from "@material-ui/core/Typography";
8 | import { auth, provider } from "../Firebase/Firebase";
9 |
10 | const useStyles = makeStyles((theme) => ({
11 | root: {
12 | boxShadow: "0 0 15px rgb(7 15 63 / 33%)",
13 | backgroundColor: "#171c30",
14 | color: "white",
15 | },
16 | paper: {
17 | marginTop: theme.spacing(10),
18 | display: "flex",
19 | flexDirection: "column",
20 | alignItems: "center",
21 | paddingBottom: "25px",
22 | paddingTop: "35px",
23 | },
24 | mainImg: {
25 | width: "100%",
26 | height: "auto",
27 | },
28 | submit: {
29 | margin: theme.spacing(3, 0, 2),
30 | color: "#d9d9d9",
31 | },
32 | }));
33 |
34 | function SignUp() {
35 | const classes = useStyles();
36 |
37 | const login = () => {
38 | auth
39 | .signInWithPopup(provider)
40 | .then((res) => {
41 | console.log("Success");
42 | })
43 | .catch((err) => {
44 | console.log(err);
45 | });
46 | };
47 |
48 | return (
49 |
50 |
51 |

52 |
53 | Sign In To Chatify
54 |
55 |
}
60 | onClick={login}
61 | >
62 | Sign In With Google
63 |
64 |
65 |
66 | );
67 | }
68 |
69 | export default SignUp;
70 |
--------------------------------------------------------------------------------
/src/Components/DeleteModal.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Button from "@material-ui/core/Button";
3 | import Dialog from "@material-ui/core/Dialog";
4 | import DialogActions from "@material-ui/core/DialogActions";
5 | import DialogContent from "@material-ui/core/DialogContent";
6 | import DialogContentText from "@material-ui/core/DialogContentText";
7 | import DialogTitle from "@material-ui/core/DialogTitle";
8 |
9 | function DeleteModal({ msgId, text, deleteMsg, handleModal, postImg }) {
10 | const [open, setOpen] = useState(true);
11 |
12 | const handleClose = () => {
13 | setOpen(false);
14 | handleModal();
15 | };
16 |
17 | const handleDelete = () => {
18 | deleteMsg(msgId);
19 | handleModal();
20 | };
21 |
22 | return (
23 |
24 |
63 |
64 | );
65 | }
66 |
67 | export default DeleteModal;
68 |
--------------------------------------------------------------------------------
/src/Components/CreateRoom.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Button from "@material-ui/core/Button";
3 | import Dialog from "@material-ui/core/Dialog";
4 | import DialogActions from "@material-ui/core/DialogActions";
5 | import DialogContent from "@material-ui/core/DialogContent";
6 | import TextField from "@material-ui/core/TextField";
7 | import DialogTitle from "@material-ui/core/DialogTitle";
8 |
9 | function CreateRoom({ create, manage }) {
10 | const [open, setOpen] = useState(true);
11 | const [roomName, setRoomName] = useState("");
12 |
13 | const handleClose = () => {
14 | setOpen(false);
15 | manage();
16 | };
17 | const handleNewRoom = (e) => {
18 | e.preventDefault();
19 | if (roomName) {
20 | create(roomName);
21 | manage();
22 | }
23 | };
24 |
25 | return (
26 |
27 |
74 |
75 | );
76 | }
77 |
78 | export default CreateRoom;
79 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import { useState, useEffect } from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import Application from "./Components/Application";
4 | import Chat from "./Components/Chat";
5 | import Login from "./Components/SignUp";
6 | import Home from "./Components/Home";
7 | import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
8 | import { auth, db } from "./Firebase/Firebase";
9 | import "./App.css";
10 |
11 | const useStyles = makeStyles((theme) => ({
12 | root: {
13 | display: "flex",
14 | },
15 | toolbar: theme.mixins.toolbar,
16 | content: {
17 | flexGrow: 1,
18 | backgroundColor: "#22273b !important",
19 | height: "100vh",
20 | },
21 | }));
22 |
23 | function App() {
24 | const classes = useStyles();
25 | const [user, setUser] = useState(null);
26 |
27 | useEffect(() => {
28 | auth.onAuthStateChanged((user) => {
29 | if (user) {
30 | db.collection("users")
31 | .doc(user.uid)
32 | .get()
33 | .then((doc) => {
34 | if (doc.exists) {
35 | console.log("user exits");
36 | } else {
37 | const details = {
38 | name: user.displayName,
39 | displayName: user.displayName.split(" ")[0],
40 | photoURL: user.photoURL,
41 | email: user.email,
42 | uid: user.uid,
43 | };
44 | db.collection("users")
45 | .doc(user.uid)
46 | .set(details)
47 | .then((res) => {
48 | console.log("new user created");
49 | })
50 | .catch((err) => {
51 | console.log(err);
52 | });
53 | }
54 | })
55 | .catch((err) => {
56 | console.log(err);
57 | });
58 |
59 | setUser(user.uid);
60 | } else {
61 | setUser(null);
62 | }
63 | });
64 | }, []);
65 |
66 | return (
67 |
68 |
69 | {!user ? (
70 |
71 | ) : (
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | )}
87 |
88 |
89 | );
90 | }
91 |
92 | export default App;
93 |
--------------------------------------------------------------------------------
/src/Components/EditProfile.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import Button from "@material-ui/core/Button";
3 | import TextField from "@material-ui/core/TextField";
4 | import Dialog from "@material-ui/core/Dialog";
5 | import DialogActions from "@material-ui/core/DialogActions";
6 | import DialogContent from "@material-ui/core/DialogContent";
7 | import DialogTitle from "@material-ui/core/DialogTitle";
8 | import { db } from "../Firebase/Firebase";
9 |
10 | function EditProfile({ toggler, alert }) {
11 | const [open, setOpen] = useState(true);
12 | const [userName, setUserName] = useState("");
13 | const [displayName, setDisplayName] = useState("");
14 | const [email, setEmail] = useState("");
15 | const [uid, setUid] = useState("");
16 |
17 | const handleClose = () => {
18 | setOpen(false);
19 | toggler();
20 | };
21 |
22 | const updateProfile = (e) => {
23 | e.preventDefault();
24 | db.collection("users")
25 | .doc(uid)
26 | .update({
27 | displayName: displayName,
28 | })
29 | .then((res) => {
30 | alert();
31 | })
32 | .catch((err) => {
33 | console.log(err);
34 | });
35 |
36 | setOpen(false);
37 | toggler();
38 | };
39 |
40 | useEffect(() => {
41 | const userData = JSON.parse(localStorage.getItem("userDetails"));
42 | setUserName(userData.name);
43 | setDisplayName(userData.displayName);
44 | setEmail(userData.email);
45 | setUid(userData.uid);
46 | }, []);
47 |
48 | return (
49 |
50 |
117 |
118 | );
119 | }
120 |
121 | export default EditProfile;
122 |
--------------------------------------------------------------------------------
/src/Components/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import Grid from "@material-ui/core/Grid";
4 | import Typography from "@material-ui/core/Typography";
5 | import Card from "@material-ui/core/Card";
6 | import CardActionArea from "@material-ui/core/CardActionArea";
7 | import CardContent from "@material-ui/core/CardContent";
8 | import Avatar from "@material-ui/core/Avatar";
9 | import { db } from "../Firebase/Firebase";
10 | import { useHistory } from "react-router-dom";
11 |
12 | const useStyles = makeStyles((theme) => ({
13 | root: {
14 | paddingTop: "50px",
15 | paddingBottom: "25px",
16 | color: "#f0f0f0",
17 | },
18 | heading: {
19 | fontSize: "2.2em",
20 | fontWeight: "700",
21 | },
22 | subHeading: {
23 | fontSize: "1.6em",
24 | },
25 | channelDiv: {
26 | padding: "15px",
27 | },
28 | channelContent: {
29 | display: "flex",
30 | flexDirection: "column",
31 | textAlign: "center",
32 | padding: "20px",
33 | alignItems: "center",
34 | },
35 | square: {
36 | height: "80px",
37 | width: "80px",
38 | backgroundColor: "#8fabbd66",
39 | fontSize: "2rem",
40 | },
41 | rootChannel: {
42 | height: "calc(100vh - 185px)",
43 | position: "relative",
44 | padding: "15px",
45 | overflowY: "scroll",
46 | },
47 | channelText: {
48 | paddingTop: "10px",
49 | fontSize: "1.2rem",
50 | },
51 | channelCard: {
52 | backgroundColor: "#1e2439",
53 | boxShadow:
54 | "0px 3px 4px -1px rgb(0 0 0 / 17%), 0px 1px 1px 0px rgb(0 0 0 / 14%), 0px 1px 3px 0px rgb(0 0 0 / 12%)",
55 | color: "rgb(220, 221, 222)",
56 | },
57 | }));
58 |
59 | function Home() {
60 | const classes = useStyles();
61 | const [channels, setChannels] = useState([]);
62 | const history = useHistory();
63 |
64 | useEffect(() => {
65 | db.collection("channels")
66 | .orderBy("channelName", "asc")
67 | .onSnapshot((snapshot) => {
68 | setChannels(
69 | snapshot.docs.map((channel) => ({
70 | channelName: channel.data().channelName,
71 | id: channel.id,
72 | }))
73 | );
74 | });
75 | }, []);
76 |
77 | const goToChannel = (id) => {
78 | history.push(`/channel/${id}`);
79 | };
80 |
81 | return (
82 |
83 |
84 |
85 |
86 | Welcome to Chatify
87 |
88 |
89 | Effortless live chat to hangout with friends!
90 |
91 |
92 |
93 |
94 |
95 | {channels.map((channel) => (
96 |
103 |
104 | goToChannel(channel.id)}
107 | >
108 |
109 |
114 | {channel.channelName.substr(0, 1).toUpperCase()}
115 |
116 |
117 | {channel.channelName}
118 |
119 |
120 |
121 |
122 |
123 | ))}
124 |
125 |
126 | );
127 | }
128 |
129 | export default Home;
130 |
--------------------------------------------------------------------------------
/src/Components/Rooms.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import List from "@material-ui/core/List";
4 | import ListItem from "@material-ui/core/ListItem";
5 | import ListItemIcon from "@material-ui/core/ListItemIcon";
6 | import ListItemText from "@material-ui/core/ListItemText";
7 | import Collapse from "@material-ui/core/Collapse";
8 | import ExpandLess from "@material-ui/icons/ExpandLess";
9 | import ExpandMore from "@material-ui/icons/ExpandMore";
10 | import IconButton from "@material-ui/core/IconButton";
11 | import Divider from "@material-ui/core/Divider";
12 | import AddIcon from "@material-ui/icons/Add";
13 | import { db } from "../Firebase/Firebase";
14 | import { useHistory } from "react-router-dom";
15 | import { IoMdChatboxes } from "react-icons/io";
16 | import { BiHash } from "react-icons/bi";
17 | import CreateRoom from "./CreateRoom";
18 | import Fade from "@material-ui/core/Fade";
19 | import Snackbar from "@material-ui/core/Snackbar";
20 | import CloseIcon from "@material-ui/icons/Close";
21 |
22 | const useStyles = makeStyles((theme) => ({
23 | nested: {
24 | paddingLeft: theme.spacing(4),
25 | },
26 | iconDesign: {
27 | fontSize: "1.5em",
28 | color: "#cb43fc",
29 | },
30 | primary: {
31 | color: "#cb43fc",
32 | },
33 | }));
34 |
35 | function Rooms() {
36 | const classes = useStyles();
37 | const [open, setOpen] = React.useState(true);
38 | const [channelList, setChannelList] = useState([]);
39 | const [showCreateRoom, setShowCreateRoom] = useState(false);
40 | const history = useHistory();
41 | const [alert, setAlert] = useState(false);
42 |
43 | useEffect(() => {
44 | db.collection("channels")
45 | .orderBy("channelName", "asc")
46 | .onSnapshot((snapshot) => {
47 | setChannelList(
48 | snapshot.docs.map((channel) => ({
49 | channelName: channel.data().channelName,
50 | id: channel.id,
51 | }))
52 | );
53 | });
54 | }, []);
55 |
56 | const handleClick = () => {
57 | setOpen(!open);
58 | };
59 |
60 | const goToChannel = (id) => {
61 | history.push(`/channel/${id}`);
62 | };
63 |
64 | const manageCreateRoomModal = () => {
65 | setShowCreateRoom(!showCreateRoom);
66 | };
67 |
68 | const handleAlert = () => {
69 | setAlert(!alert);
70 | };
71 |
72 | const addChannel = (cName) => {
73 | if (cName) {
74 | cName = cName.toLowerCase().trim();
75 | if (cName === "") {
76 | handleAlert();
77 | return;
78 | }
79 |
80 | for (var i = 0; i < channelList.length; i++) {
81 | if (cName === channelList[i].channelName) {
82 | handleAlert();
83 | return;
84 | }
85 | }
86 |
87 | db.collection("channels")
88 | .add({ channelName: cName.toLowerCase() })
89 | .then((res) => {
90 | console.log("added new channel");
91 | })
92 | .then((err) => {
93 | console.log(err);
94 | });
95 | }
96 | };
97 |
98 | return (
99 |
100 |
109 |
110 |
111 | }
112 | />
113 |
114 | {showCreateRoom ? (
115 |
116 | ) : null}
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 | {open ? (
132 |
133 | ) : (
134 |
135 | )}
136 |
137 |
138 |
139 |
140 | {channelList.map((channel) => (
141 | goToChannel(channel.id)}
146 | >
147 |
148 |
152 |
153 |
161 |
162 | ))}
163 |
164 |
165 |
166 |
167 | );
168 | }
169 |
170 | export default Rooms;
171 |
--------------------------------------------------------------------------------
/src/Components/FileUpload.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import { makeStyles } from "@material-ui/core/styles";
3 | import Button from "@material-ui/core/Button";
4 | import Dialog from "@material-ui/core/Dialog";
5 | import DialogActions from "@material-ui/core/DialogActions";
6 | import DialogContent from "@material-ui/core/DialogContent";
7 | import DialogTitle from "@material-ui/core/DialogTitle";
8 | import TextField from "@material-ui/core/TextField";
9 | import LinearProgress from "@material-ui/core/LinearProgress";
10 | import Typography from "@material-ui/core/Typography";
11 | import Box from "@material-ui/core/Box";
12 | import { storage } from "../Firebase/Firebase";
13 | import { useParams } from "react-router-dom";
14 | import firebase from "firebase/app";
15 | import { db } from "../Firebase/Firebase";
16 |
17 | const useStyles = makeStyles((theme) => ({
18 | displayImage: {
19 | height: "105px",
20 | width: "180px",
21 | },
22 | imageName: {
23 | paddingLeft: "15px",
24 | fontSize: "1.3em",
25 | },
26 | imageDiv: {
27 | marginLeft: "16px",
28 | marginRight: "16px",
29 | marginTop: "-33px",
30 | },
31 | }));
32 |
33 | function FileUpload({ setState, file }) {
34 | const params = useParams();
35 | const classes = useStyles();
36 | const [open, setOpen] = useState(true);
37 | const [progress, setProgress] = useState(0);
38 | const [progressBar, setProgressBar] = useState({ display: "none" });
39 | const [message, setMessage] = useState("");
40 |
41 | const handleClose = () => {
42 | setOpen(false);
43 | setState();
44 | };
45 |
46 | const sendMsg = (downloadURL) => {
47 | if (params.id) {
48 | const userData = JSON.parse(localStorage.getItem("userDetails"));
49 |
50 | if (userData) {
51 | const displayName = userData.displayName;
52 | const imgUrl = userData.photoURL;
53 | const uid = userData.uid;
54 | const likeCount = 0;
55 | const likes = {};
56 | const fireCount = 0;
57 | const fire = {};
58 | const heartCount = 0;
59 | const heart = {};
60 | const postImg = downloadURL;
61 | const obj = {
62 | text: message,
63 | timestamp: firebase.firestore.Timestamp.now(),
64 | userImg: imgUrl,
65 | userName: displayName,
66 | uid: uid,
67 | likeCount: likeCount,
68 | likes: likes,
69 | fireCount: fireCount,
70 | fire: fire,
71 | heartCount: heartCount,
72 | heart: heart,
73 | postImg: postImg,
74 | };
75 |
76 | db.collection("channels")
77 | .doc(params.id)
78 | .collection("messages")
79 | .add(obj)
80 | .then((res) => {
81 | console.log("message sent");
82 | })
83 | .catch((err) => {
84 | console.log(err);
85 | });
86 | }
87 |
88 | setMessage("");
89 | }
90 | };
91 |
92 | const fileObj = URL.createObjectURL(file);
93 |
94 | const handleUpload = (e) => {
95 | e.preventDefault();
96 | setProgressBar({ display: "block" });
97 | const uploadRef = storage.ref(`images/${file.name}`).put(file);
98 | uploadRef.on(
99 | "state_changed",
100 | (snapshot) => {
101 | // Observe state change events such as progress, pause, and resume
102 | // Get task progress, including the number of bytes uploaded and the total number of bytes to be uploaded
103 | let progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
104 | setProgress(progress);
105 | },
106 | (error) => {
107 | console.log(error);
108 | },
109 | () => {
110 | // Handle successful uploads on complete
111 | // For instance, get the download URL: https://firebasestorage.googleapis.com/...
112 | uploadRef.snapshot.ref.getDownloadURL().then((downloadURL) => {
113 | sendMsg(downloadURL);
114 | });
115 | handleClose();
116 | }
117 | );
118 | };
119 |
120 | return (
121 |
122 |
184 |
185 | );
186 | }
187 |
188 | export default FileUpload;
189 |
--------------------------------------------------------------------------------
/src/Components/Chat.js:
--------------------------------------------------------------------------------
1 | import React, { useEffect, useState } from "react";
2 | import TextField from "@material-ui/core/TextField";
3 | import { makeStyles } from "@material-ui/core/styles";
4 | import Grid from "@material-ui/core/Grid";
5 | import Messages from "./Messages";
6 | import IconButton from "@material-ui/core/IconButton";
7 | import { useParams } from "react-router-dom";
8 | import { db } from "../Firebase/Firebase";
9 | import firebase from "firebase/app";
10 | import ScrollableFeed from "react-scrollable-feed";
11 | import { BiHash } from "react-icons/bi";
12 | import { FiSend } from "react-icons/fi";
13 | import { GrEmoji } from "react-icons/gr";
14 | import { Picker } from "emoji-mart";
15 | import { RiImageAddLine } from "react-icons/ri";
16 | import FileUpload from "./FileUpload";
17 | import "emoji-mart/css/emoji-mart.css";
18 |
19 | const useStyles = makeStyles((theme) => ({
20 | root: {
21 | flexGrow: 1,
22 | },
23 | chat: {
24 | position: "relative",
25 | height: "calc(100vh - 200px)",
26 | paddingLeft: "10px",
27 | paddingBottom: "5px",
28 | paddingTop: "5px",
29 | },
30 | footer: {
31 | paddingRight: "15px",
32 | paddingLeft: "15px",
33 | paddingTop: "10px",
34 | },
35 | message: {
36 | width: "100%",
37 | color: "white",
38 | },
39 | roomName: {
40 | border: "1px solid #0000004a",
41 | borderLeft: 0,
42 | borderRight: 0,
43 | padding: "15px",
44 | display: "flex",
45 | color: "#e5e5e5",
46 | },
47 | roomNameText: {
48 | marginBlockEnd: 0,
49 | marginBlockStart: 0,
50 | paddingLeft: "5px",
51 | },
52 | iconDesign: {
53 | fontSize: "1.5em",
54 | color: "#e5e5e5",
55 | },
56 | footerContent: {
57 | display: "flex",
58 | backgroundColor: "#303753",
59 | borderRadius: "5px",
60 | alignItems: "center",
61 | },
62 | inputFile: {
63 | display: "none",
64 | },
65 | }));
66 |
67 | function Chat() {
68 | const classes = useStyles();
69 | const params = useParams();
70 | const [allMessages, setAllMessages] = useState([]);
71 | const [channelName, setChannelName] = useState("");
72 | const [userNewMsg, setUserNewMsg] = useState("");
73 | const [emojiBtn, setEmojiBtn] = useState(false);
74 | const [modalState, setModalState] = useState(false);
75 | const [file, setFileName] = useState(null);
76 |
77 | useEffect(() => {
78 | if (params.id) {
79 | db.collection("channels")
80 | .doc(params.id)
81 | .onSnapshot((snapshot) => {
82 | setChannelName(snapshot.data().channelName);
83 | });
84 |
85 | db.collection("channels")
86 | .doc(params.id)
87 | .collection("messages")
88 | .orderBy("timestamp", "asc")
89 | .onSnapshot((snapshot) => {
90 | setAllMessages(
91 | snapshot.docs.map((doc) => ({ id: doc.id, data: doc.data() }))
92 | );
93 | });
94 | }
95 | }, [params]);
96 |
97 | const sendMsg = (e) => {
98 | e.preventDefault();
99 | if (userNewMsg && params.id) {
100 | const userData = JSON.parse(localStorage.getItem("userDetails"));
101 |
102 | if (userData) {
103 | const displayName = userData.displayName;
104 | const imgUrl = userData.photoURL;
105 | const uid = userData.uid;
106 | const likeCount = 0;
107 | const likes = {};
108 | const fireCount = 0;
109 | const fire = {};
110 | const heartCount = 0;
111 | const heart = {};
112 | const postImg = null;
113 | const obj = {
114 | text: userNewMsg,
115 | timestamp: firebase.firestore.Timestamp.now(),
116 | userImg: imgUrl,
117 | userName: displayName,
118 | uid: uid,
119 | likeCount: likeCount,
120 | likes: likes,
121 | fireCount: fireCount,
122 | fire: fire,
123 | heartCount: heartCount,
124 | heart: heart,
125 | postImg: postImg,
126 | };
127 |
128 | db.collection("channels")
129 | .doc(params.id)
130 | .collection("messages")
131 | .add(obj)
132 | .then((res) => {
133 | console.log("message sent");
134 | })
135 | .catch((err) => {
136 | console.log(err);
137 | });
138 | }
139 |
140 | setUserNewMsg("");
141 | setEmojiBtn(false);
142 | }
143 | };
144 |
145 | const addEmoji = (e) => {
146 | setUserNewMsg(userNewMsg + e.native);
147 | };
148 |
149 | const openModal = () => {
150 | setModalState(!modalState);
151 | };
152 |
153 | const handelFileUpload = (e) => {
154 | e.preventDefault();
155 | if (e.target.files[0]) {
156 | setFileName(e.target.files[0]);
157 | openModal();
158 | }
159 | e.target.value = null;
160 | };
161 |
162 | return (
163 |
164 | {modalState ?
: null}
165 |
166 |
167 | {channelName}
168 |
169 |
170 |
171 | {allMessages.map((message) => (
172 |
177 | ))}
178 |
179 |
180 |
233 |
234 | );
235 | }
236 |
237 | export default Chat;
238 |
--------------------------------------------------------------------------------
/src/Components/Application.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import AppBar from "@material-ui/core/AppBar";
3 | import CssBaseline from "@material-ui/core/CssBaseline";
4 | import Divider from "@material-ui/core/Divider";
5 | import Drawer from "@material-ui/core/Drawer";
6 | import Hidden from "@material-ui/core/Hidden";
7 | import IconButton from "@material-ui/core/IconButton";
8 | import MenuIcon from "@material-ui/icons/Menu";
9 | import Toolbar from "@material-ui/core/Toolbar";
10 | import Typography from "@material-ui/core/Typography";
11 | import { makeStyles, useTheme, withStyles } from "@material-ui/core/styles";
12 | import AccountCircle from "@material-ui/icons/AccountCircle";
13 | import MenuItem from "@material-ui/core/MenuItem";
14 | import Menu from "@material-ui/core/Menu";
15 | import Badge from "@material-ui/core/Badge";
16 | import Avatar from "@material-ui/core/Avatar";
17 | import { Grid } from "@material-ui/core";
18 | import { deepPurple } from "@material-ui/core/colors";
19 | import Rooms from "./Rooms";
20 | import { GoSignOut } from "react-icons/go";
21 | import { FaUserEdit } from "react-icons/fa";
22 | import { auth, db } from "../Firebase/Firebase";
23 | import { Link } from "react-router-dom";
24 | import EditProfile from "./EditProfile";
25 | import Fade from "@material-ui/core/Fade";
26 | import Snackbar from "@material-ui/core/Snackbar";
27 | import CloseIcon from "@material-ui/icons/Close";
28 |
29 | const drawerWidth = 240;
30 |
31 | const StyledBadge = withStyles((theme) => ({
32 | badge: {
33 | backgroundColor: "#44b700",
34 | color: "#44b700",
35 | boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
36 | "&::after": {
37 | position: "absolute",
38 | top: 0,
39 | left: 0,
40 | width: "100%",
41 | height: "100%",
42 | borderRadius: "50%",
43 | border: "1px solid currentColor",
44 | content: '""',
45 | },
46 | },
47 | "@keyframes ripple": {
48 | "0%": {
49 | transform: "scale(.8)",
50 | opacity: 1,
51 | },
52 | "100%": {
53 | transform: "scale(2.4)",
54 | opacity: 0,
55 | },
56 | },
57 | }))(Badge);
58 |
59 | const useStyles = makeStyles((theme) => ({
60 | root: {
61 | display: "flex",
62 | },
63 | avatarGrid: {
64 | paddingTop: "20px",
65 | paddingLeft: "5px",
66 | paddingBottom: "20px",
67 | color: "#dcddde",
68 | },
69 | avatarIcon: {
70 | display: "flex",
71 | paddingLeft: "10px",
72 | paddingRight: "10px",
73 | },
74 | avatarName: {
75 | fontSize: "1em",
76 | paddingLeft: "12px",
77 | paddingTop: "8px",
78 | },
79 | avatarDisplayName: {
80 | alignSelf: "center",
81 | paddingLeft: "10px",
82 | fontWeight: "600",
83 | },
84 | purple: {
85 | color: theme.palette.getContrastText(deepPurple[500]),
86 | backgroundColor: "#3f51b5",
87 | },
88 | drawer: {
89 | [theme.breakpoints.up("sm")]: {
90 | width: drawerWidth,
91 | flexShrink: 0,
92 | },
93 | },
94 | appBar: {
95 | [theme.breakpoints.up("sm")]: {
96 | width: `calc(100% - ${drawerWidth}px)`,
97 | marginLeft: drawerWidth,
98 | },
99 | backgroundColor: "#22273b",
100 | color: "#dcddde",
101 | boxShadow:
102 | "0 1px 0 rgba(4,4,5,0.2),0 1.5px 0 rgba(6,6,7,0.05),0 2px 0 rgba(4,4,5,0.05);",
103 | },
104 | menuButton: {
105 | marginRight: theme.spacing(2),
106 | [theme.breakpoints.up("sm")]: {
107 | display: "none",
108 | },
109 | },
110 | // necessary for content to be below app bar
111 | toolbar: theme.mixins.toolbar,
112 | drawerPaper: {
113 | width: drawerWidth,
114 | backgroundColor: "#171c2e",
115 | color: "white",
116 | },
117 | sideToolBar: {
118 | backgroundColor: "#171c2e",
119 | color: "#fff",
120 | lineHeight: 1.6,
121 | boxShadow:
122 | "0 1px 0 rgba(4,4,5,0.2),0 1.5px 0 rgba(6,6,7,0.05),0 2px 0 rgba(4,4,5,0.05);",
123 | minHeight: "50px",
124 | },
125 | sideToolBarText: {
126 | letterSpacing: "0.2em",
127 | fontWeight: "900",
128 | },
129 | title: {
130 | flexGrow: 1,
131 | },
132 | }));
133 |
134 | function Application(props) {
135 | const { window, uid } = props;
136 | const classes = useStyles();
137 | const theme = useTheme();
138 | const [mobileOpen, setMobileOpen] = React.useState(false);
139 | const [anchorEl, setAnchorEl] = React.useState(null);
140 | const [userDetails, setUserDetails] = useState([]);
141 | const [editProfileModal, setEditProfileModal] = useState(false);
142 | const [alert, setAlert] = useState(false);
143 | const open = Boolean(anchorEl);
144 |
145 | useEffect(() => {
146 | db.collection("users")
147 | .doc(uid)
148 | .onSnapshot((doc) => {
149 | setUserDetails(doc.data());
150 | localStorage.setItem("userDetails", JSON.stringify(doc.data()));
151 | });
152 | }, [uid]);
153 |
154 | const handleMenu = (event) => {
155 | setAnchorEl(event.currentTarget);
156 | };
157 |
158 | const handleClose = () => {
159 | setAnchorEl(null);
160 | };
161 |
162 | const handleDrawerToggle = () => {
163 | setMobileOpen(!mobileOpen);
164 | };
165 |
166 | const toggleEditProfile = () => {
167 | setEditProfileModal(!editProfileModal);
168 | };
169 |
170 | const handleAlert = () => {
171 | setAlert(!alert);
172 | };
173 |
174 | const signOut = () => {
175 | auth
176 | .signOut()
177 | .then(() => {
178 | console.log("signed out");
179 | localStorage.clear();
180 | })
181 | .catch((err) => {
182 | console.log(err);
183 | });
184 | };
185 |
186 | const drawer = userDetails && (
187 |
188 |
189 |
190 | CHATIFY
191 |
192 |
193 |
194 |
195 |
196 |
204 |
209 |
210 |
211 | {userDetails.displayName}
212 |
213 |
214 |
215 |
216 | {userDetails.name}
217 |
218 |
219 | {userDetails.email}
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 | );
228 |
229 | const container =
230 | window !== undefined ? () => window().document.body : undefined;
231 | return (
232 |
233 |
234 |
235 |
244 |
245 |
246 | }
247 | />
248 |
249 | {editProfileModal ? (
250 |
251 | ) : null}
252 |
253 |
254 |
255 |
262 |
263 |
264 |
265 |
266 |
267 | Home
268 |
269 |
270 |
271 |
272 |
279 |
280 |
281 |
305 |
306 |
307 |
308 |
309 |
341 |
342 | );
343 | }
344 |
345 | export default Application;
346 |
--------------------------------------------------------------------------------
/src/Components/Messages.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Grid from "@material-ui/core/Grid";
3 | import { makeStyles } from "@material-ui/core/styles";
4 | import Avatar from "@material-ui/core/Avatar";
5 | import { deepPurple } from "@material-ui/core/colors";
6 | import IconButton from "@material-ui/core/IconButton";
7 | import { AiFillLike } from "react-icons/ai";
8 | import { AiFillFire } from "react-icons/ai";
9 | import { AiFillHeart } from "react-icons/ai";
10 | import { AiFillDelete } from "react-icons/ai";
11 | import { db } from "../Firebase/Firebase";
12 | import { useParams } from "react-router-dom";
13 | import DeleteModal from "./DeleteModal";
14 | import { Anchorme } from "react-anchorme";
15 |
16 | const useStyles = makeStyles((theme) => ({
17 | root: {
18 | flexGrow: 1,
19 | position: "relative",
20 | padding: "8px",
21 | },
22 | paper: {
23 | padding: "10px",
24 | "&:hover": {
25 | backgroundColor: "#1f2436",
26 | },
27 | },
28 | avatar: {
29 | display: "inline-block",
30 | verticalAlign: "top",
31 | },
32 | chat: {
33 | display: "inline-block",
34 | paddingLeft: "1rem",
35 | width: "calc(100% - 50px)",
36 | wordBreak: "break-all",
37 | },
38 | chatHeading: {
39 | marginBlockStart: 0,
40 | marginBlockEnd: 0,
41 | display: "inline-block",
42 | fontSize: "1rem",
43 | fontWeight: "600",
44 | color: "white",
45 | },
46 | chatTimming: {
47 | marginBlockStart: 0,
48 | marginBlockEnd: 0,
49 | display: "inline-block",
50 | paddingLeft: "0.5em",
51 | color: "white",
52 | },
53 | chatText: {
54 | color: "#dcddde",
55 | },
56 | purple: {
57 | color: theme.palette.getContrastText(deepPurple[500]),
58 | backgroundColor: "#3f51b5",
59 | },
60 | emojiDiv: {
61 | position: "absolute",
62 | right: 0,
63 | top: 0,
64 | },
65 | emojiDivInner: {
66 | position: "absolute",
67 | right: 0,
68 | padding: "0 35px 0 32px",
69 | },
70 | emojiBtn: {
71 | fontSize: "1.1rem",
72 | color: "rgb(255 195 54)",
73 | },
74 | allEmoji: {
75 | backgroundColor: "#2d2e31ba",
76 | borderRadius: "5px",
77 | paddingLeft: "2px",
78 | paddingRight: "2px",
79 | display: "flex",
80 | },
81 | countEmojiBtn: {
82 | padding: "3px",
83 | borderRadius: "4px",
84 | fontSize: "0.8em",
85 | backgroundColor: "#ffffff4a",
86 | color: "#cacaca",
87 | paddingLeft: "5px",
88 | paddingRight: "5px",
89 | "&:hover": {
90 | backgroundColor: "#ffffff4a",
91 | color: "#e7e7e7",
92 | },
93 | },
94 | }));
95 |
96 | function Messages({ values, msgId }) {
97 | const [style, setStyle] = useState({ display: "none" });
98 | const [deleteModal, setDeleteModal] = useState(false);
99 | const classes = useStyles();
100 |
101 | const uid = JSON.parse(localStorage.getItem("userDetails")).uid;
102 | const messegerUid = values.uid;
103 | const date = values.timestamp.toDate();
104 | const day = date.getDate();
105 | const year = date.getFullYear();
106 | const month = date.getMonth();
107 | const hour = date.getHours();
108 | const minute = date.getMinutes();
109 | const time = `${day}/${month}/${year} ${hour}:${minute}`;
110 |
111 | const numLikes = values.likeCount;
112 | const numFire = values.fireCount;
113 | const numHeart = values.heartCount;
114 |
115 | const userLiked = values.likes[uid];
116 | const userFire = values.fire[uid];
117 | const userHeart = values.heart[uid];
118 |
119 | const postImg = values.postImg;
120 |
121 | const channelId = useParams().id;
122 |
123 | const selectedLike = userLiked
124 | ? { color: "#8ff879", backgroundColor: "#545454" }
125 | : null;
126 |
127 | const selectedHeart = userHeart
128 | ? { color: "#ff527d", backgroundColor: "#545454" }
129 | : null;
130 |
131 | const selectedFire = userFire
132 | ? { color: "#ffc336", backgroundColor: "#545454" }
133 | : null;
134 |
135 | const showDeleteModal = () => {
136 | setDeleteModal(!deleteModal);
137 | };
138 |
139 | const heartClick = () => {
140 | const messageDoc = db
141 | .collection("channels")
142 | .doc(channelId)
143 | .collection("messages")
144 | .doc(msgId);
145 | if (userHeart) {
146 | return db
147 | .runTransaction((transaction) => {
148 | // This code may get re-run multiple times if there are conflicts.
149 | return transaction.get(messageDoc).then((doc) => {
150 | if (!doc) {
151 | console.log("doc not found");
152 | return;
153 | }
154 |
155 | let newHeartCount = doc.data().heartCount - 1;
156 | let newHeart = doc.data().heart ? doc.data().heart : {};
157 | newHeart[uid] = false;
158 |
159 | transaction.update(messageDoc, {
160 | heartCount: newHeartCount,
161 | heart: newHeart,
162 | });
163 | });
164 | })
165 | .then(() => {
166 | console.log("Disiked");
167 | })
168 | .catch((error) => {
169 | console.log(error);
170 | });
171 | } else {
172 | return db
173 | .runTransaction((transaction) => {
174 | // This code may get re-run multiple times if there are conflicts.
175 | return transaction.get(messageDoc).then((doc) => {
176 | if (!doc) {
177 | console.log("doc not found");
178 | return;
179 | }
180 |
181 | let newHeartCount = doc.data().heartCount + 1;
182 | let newHeart = doc.data().heart ? doc.data().heart : {};
183 | newHeart[uid] = true;
184 |
185 | transaction.update(messageDoc, {
186 | heartCount: newHeartCount,
187 | heart: newHeart,
188 | });
189 | });
190 | })
191 | .then(() => {
192 | console.log("Liked");
193 | })
194 | .catch((error) => {
195 | console.log(error);
196 | });
197 | }
198 | };
199 |
200 | const fireClick = () => {
201 | const messageDoc = db
202 | .collection("channels")
203 | .doc(channelId)
204 | .collection("messages")
205 | .doc(msgId);
206 | if (userFire) {
207 | return db
208 | .runTransaction((transaction) => {
209 | // This code may get re-run multiple times if there are conflicts.
210 | return transaction.get(messageDoc).then((doc) => {
211 | if (!doc) {
212 | console.log("doc not found");
213 | return;
214 | }
215 |
216 | let newFireCount = doc.data().fireCount - 1;
217 | let newFire = doc.data().fire ? doc.data().fire : {};
218 | newFire[uid] = false;
219 |
220 | transaction.update(messageDoc, {
221 | fireCount: newFireCount,
222 | fire: newFire,
223 | });
224 | });
225 | })
226 | .then(() => {
227 | console.log("Disiked");
228 | })
229 | .catch((error) => {
230 | console.log(error);
231 | });
232 | } else {
233 | return db
234 | .runTransaction((transaction) => {
235 | // This code may get re-run multiple times if there are conflicts.
236 | return transaction.get(messageDoc).then((doc) => {
237 | if (!doc) {
238 | console.log("doc not found");
239 | return;
240 | }
241 |
242 | let newFireCount = doc.data().fireCount + 1;
243 | let newFire = doc.data().fire ? doc.data().fire : {};
244 | newFire[uid] = true;
245 |
246 | transaction.update(messageDoc, {
247 | fireCount: newFireCount,
248 | fire: newFire,
249 | });
250 | });
251 | })
252 | .then(() => {
253 | console.log("Liked");
254 | })
255 | .catch((error) => {
256 | console.log(error);
257 | });
258 | }
259 | };
260 |
261 | const likeClick = () => {
262 | const messageDoc = db
263 | .collection("channels")
264 | .doc(channelId)
265 | .collection("messages")
266 | .doc(msgId);
267 | if (userLiked) {
268 | return db
269 | .runTransaction((transaction) => {
270 | // This code may get re-run multiple times if there are conflicts.
271 | return transaction.get(messageDoc).then((doc) => {
272 | if (!doc) {
273 | console.log("doc not found");
274 | return;
275 | }
276 |
277 | let newLikeCount = doc.data().likeCount - 1;
278 | let newLikes = doc.data().likes ? doc.data().likes : {};
279 | newLikes[uid] = false;
280 |
281 | transaction.update(messageDoc, {
282 | likeCount: newLikeCount,
283 | likes: newLikes,
284 | });
285 | });
286 | })
287 | .then(() => {
288 | console.log("Disiked");
289 | })
290 | .catch((error) => {
291 | console.log(error);
292 | });
293 | } else {
294 | return db
295 | .runTransaction((transaction) => {
296 | // This code may get re-run multiple times if there are conflicts.
297 | return transaction.get(messageDoc).then((doc) => {
298 | if (!doc) {
299 | console.log("doc not found");
300 | return;
301 | }
302 |
303 | let newLikeCount = doc.data().likeCount + 1;
304 | let newLikes = doc.data().likes ? doc.data().likes : {};
305 | newLikes[uid] = true;
306 |
307 | transaction.update(messageDoc, {
308 | likeCount: newLikeCount,
309 | likes: newLikes,
310 | });
311 | });
312 | })
313 | .then(() => {
314 | console.log("Liked");
315 | })
316 | .catch((error) => {
317 | console.log(error);
318 | });
319 | }
320 | };
321 |
322 | const deleteMsg = (id) => {
323 | db.collection("channels")
324 | .doc(channelId)
325 | .collection("messages")
326 | .doc(id)
327 | .delete()
328 | .then((res) => {
329 | console.log("deleted successfully");
330 | })
331 | .catch((err) => {
332 | console.log(err);
333 | });
334 | };
335 |
336 | return (
337 |
338 | {deleteModal ? (
339 |
346 | ) : null}
347 | {
350 | setStyle({ display: "block" });
351 | }}
352 | onMouseLeave={(e) => {
353 | setStyle({ display: "none" });
354 | }}
355 | >
356 |
363 |
364 |
365 |
366 |
{values.userName}
367 |
{time}
368 |
369 |
370 |
371 | {values.text.split("\n").map((txt, idx) => (
372 |
373 |
374 | {txt}
375 |
376 |
377 | ))}
378 |
379 |
380 |
381 | {postImg ? (
382 |
387 | ) : null}
388 |
389 |
390 |
391 | {numLikes > 0 ? (
392 |
393 |
399 |
400 | {numLikes}
401 |
402 |
403 | ) : null}
404 |
405 | {numFire > 0 ? (
406 |
407 |
413 |
414 | {numFire}
415 |
416 |
417 | ) : null}
418 |
419 | {numHeart > 0 ? (
420 |
421 |
427 |
428 | {numHeart}
429 |
430 |
431 | ) : null}
432 |
433 |
434 |
435 |
436 |
437 |
438 |
443 |
444 |
445 |
450 |
451 |
452 |
457 |
458 |
459 | {uid === messegerUid ? (
460 |
465 |
469 |
470 | ) : null}
471 |
472 |
473 |
474 |
475 |
476 | );
477 | }
478 |
479 | export default Messages;
480 |
--------------------------------------------------------------------------------