├── frontend
├── src
│ ├── redux
│ │ ├── noteRedux.js
│ │ ├── apiCalls.js
│ │ ├── store.js
│ │ └── userRedux.js
│ ├── pages
│ │ ├── home
│ │ │ ├── right
│ │ │ │ ├── Right.jsx
│ │ │ │ └── right.css
│ │ │ ├── center
│ │ │ │ ├── Homepost.js
│ │ │ │ └── RenderPost.js
│ │ │ ├── Home.css
│ │ │ ├── Home.jsx
│ │ │ └── left
│ │ │ │ ├── HomeProfile.css
│ │ │ │ └── Homeprofile.jsx
│ │ ├── searchUserPage
│ │ │ └── SearchUserPage.jsx
│ │ ├── messenger
│ │ │ ├── messenger.css
│ │ │ └── messenger.jsx
│ │ ├── login
│ │ │ └── Login.jsx
│ │ ├── register
│ │ │ └── Register.jsx
│ │ └── profile
│ │ │ ├── Profile.css
│ │ │ └── Profile.js
│ ├── component
│ │ ├── BuildConversation
│ │ │ ├── BuildConversation.css
│ │ │ └── BuildConversation.jsx
│ │ ├── CircularLoader.jsx
│ │ ├── message
│ │ │ ├── Message.jsx
│ │ │ └── message.css
│ │ ├── chatOnline
│ │ │ ├── chatOnline.css
│ │ │ └── chatOnline.jsx
│ │ ├── conversations
│ │ │ ├── conversation.css
│ │ │ └── Conversation.jsx
│ │ ├── comment
│ │ │ ├── CommentBox.css
│ │ │ ├── CommentBox.js
│ │ │ ├── Comment.css
│ │ │ └── Comment.js
│ │ ├── TopNavbar
│ │ │ ├── TopNavbar.jsx
│ │ │ └── Navbar.style.js
│ │ ├── updatepost
│ │ │ ├── UpdatePost.css
│ │ │ └── UpdatePost.js
│ │ ├── footer
│ │ │ ├── Footer.jsx
│ │ │ └── Footer.css
│ │ ├── banner
│ │ │ ├── Banner.css
│ │ │ └── Banner.jsx
│ │ ├── Author
│ │ │ ├── Author.css
│ │ │ └── Author.jsx
│ │ ├── SearchedUser
│ │ │ └── SearchedUser.jsx
│ │ ├── uploadNote
│ │ │ ├── UploadNote.css
│ │ │ └── UploadNote.js
│ │ ├── updateUser
│ │ │ ├── UpdateUser.css
│ │ │ └── UpdateUser.js
│ │ ├── topbar
│ │ │ ├── Topbar.jsx
│ │ │ └── Topbar.css
│ │ ├── post
│ │ │ ├── Post.css
│ │ │ └── Post.js
│ │ └── Navbar.jsx
│ ├── responsive.js
│ ├── requestMethods.js
│ ├── index.js
│ ├── loader
│ │ └── Loader.js
│ └── App.js
├── .env
├── public
│ ├── image
│ │ ├── chat.png
│ │ ├── home.png
│ │ ├── searchuser.png
│ │ ├── uploadform.png
│ │ ├── userprofile.png
│ │ ├── icons8-like-64.png
│ │ ├── icons8-view-50.png
│ │ ├── icons8-view-64.png
│ │ ├── icons8-delete-90.png
│ │ ├── icons8-edit-100.png
│ │ ├── icons8-like-post.png
│ │ ├── fast-forward-button.png
│ │ ├── icons8-comment-64.png
│ │ ├── icons8-liked-post.png
│ │ ├── icons8-chat-bubble-90.png
│ │ ├── icons8-vertical-line.png
│ │ └── icons8-microsoft-publisher-50.png
│ ├── music
│ │ ├── like.wav
│ │ ├── delete.wav
│ │ ├── error.wav
│ │ ├── follow.wav
│ │ ├── update.wav
│ │ ├── comment.wav
│ │ └── mixkit-positive-interface-click-1112.wav
│ └── index.html
├── .gitignore
├── README.md
└── package.json
├── backend
├── .gitignore
├── public
│ └── images
│ │ ├── DefaultBoy.jpg
│ │ ├── DefaultGirl.jpg
│ │ ├── DefaultPic.png
│ │ └── images-notes.jpg
├── .env
├── model
│ ├── Conversation.js
│ ├── Message.js
│ ├── Commentschema.js
│ ├── Noteschema.js
│ └── Userschema.js
├── database
│ └── db.js
├── package.json
├── routes
│ ├── message.js
│ ├── comment.js
│ ├── auth.js
│ ├── conversation.js
│ ├── users.js
│ └── notes.js
└── index.js
├── socket
├── README.md
├── router.js
├── .gitignore
├── package.json
└── index.js
├── LICENSE
└── README.md
/frontend/src/redux/noteRedux.js:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/backend/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/right/Right.jsx:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/right/right.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/src/component/BuildConversation/BuildConversation.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/frontend/.env:
--------------------------------------------------------------------------------
1 | REACT_APP_PUBLIC_FOLDER="https://notesharingbackend-ankitkr437.onrender.com/images/"
--------------------------------------------------------------------------------
/socket/README.md:
--------------------------------------------------------------------------------
1 | # Handnote-Socket
2 | #### Main route of this server "https://handnotesocket.herokuapp.com/"
3 |
--------------------------------------------------------------------------------
/frontend/public/image/chat.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/chat.png
--------------------------------------------------------------------------------
/frontend/public/image/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/home.png
--------------------------------------------------------------------------------
/frontend/public/music/like.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/like.wav
--------------------------------------------------------------------------------
/frontend/public/music/delete.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/delete.wav
--------------------------------------------------------------------------------
/frontend/public/music/error.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/error.wav
--------------------------------------------------------------------------------
/frontend/public/music/follow.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/follow.wav
--------------------------------------------------------------------------------
/frontend/public/music/update.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/update.wav
--------------------------------------------------------------------------------
/frontend/public/music/comment.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/comment.wav
--------------------------------------------------------------------------------
/backend/public/images/DefaultBoy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/backend/public/images/DefaultBoy.jpg
--------------------------------------------------------------------------------
/backend/public/images/DefaultGirl.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/backend/public/images/DefaultGirl.jpg
--------------------------------------------------------------------------------
/backend/public/images/DefaultPic.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/backend/public/images/DefaultPic.png
--------------------------------------------------------------------------------
/frontend/public/image/searchuser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/searchuser.png
--------------------------------------------------------------------------------
/frontend/public/image/uploadform.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/uploadform.png
--------------------------------------------------------------------------------
/frontend/public/image/userprofile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/userprofile.png
--------------------------------------------------------------------------------
/backend/public/images/images-notes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/backend/public/images/images-notes.jpg
--------------------------------------------------------------------------------
/frontend/public/image/icons8-like-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-like-64.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-view-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-view-50.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-view-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-view-64.png
--------------------------------------------------------------------------------
/backend/.env:
--------------------------------------------------------------------------------
1 | USERNAME=ankit
2 | PASSWORD=123
3 | URL='mongodb+srv://ankit:123@cluster0.orv6uim.mongodb.net/?retryWrites=true&w=majority'
4 |
--------------------------------------------------------------------------------
/frontend/public/image/icons8-delete-90.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-delete-90.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-edit-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-edit-100.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-like-post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-like-post.png
--------------------------------------------------------------------------------
/frontend/public/image/fast-forward-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/fast-forward-button.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-comment-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-comment-64.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-liked-post.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-liked-post.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-chat-bubble-90.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-chat-bubble-90.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-vertical-line.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-vertical-line.png
--------------------------------------------------------------------------------
/frontend/public/image/icons8-microsoft-publisher-50.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/image/icons8-microsoft-publisher-50.png
--------------------------------------------------------------------------------
/frontend/public/music/mixkit-positive-interface-click-1112.wav:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ankitkr437/NoteSharing/HEAD/frontend/public/music/mixkit-positive-interface-click-1112.wav
--------------------------------------------------------------------------------
/frontend/src/responsive.js:
--------------------------------------------------------------------------------
1 | import { css } from "styled-components";
2 |
3 | export const mobile = (props) => {
4 | return css`
5 | @media only screen and (max-width: 480px) {
6 | ${props}
7 | }
8 | `;
9 | };
--------------------------------------------------------------------------------
/socket/router.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 |
4 | router.get("/", (req, res) => {
5 | res.send({ response: "Server is up and running." }).status(200);
6 | });
7 |
8 | module.exports = router;
--------------------------------------------------------------------------------
/backend/model/Conversation.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const ConversationSchema = new mongoose.Schema(
4 | {
5 | members: {
6 | type: Array,
7 | },
8 | },
9 | { timestamps: true }
10 | );
11 |
12 |
13 | const Conversation =mongoose.model("Conversation",ConversationSchema);
14 | export default Conversation ;
--------------------------------------------------------------------------------
/backend/model/Message.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const MessageSchema = new mongoose.Schema(
4 | {
5 | conversationId: {
6 | type: String,
7 | },
8 | sender: {
9 | type: String,
10 | },
11 | text: {
12 | type: String,
13 | },
14 | },
15 | { timestamps: true }
16 | );
17 |
18 | const Message= mongoose.model("Message", MessageSchema);
19 | export default Message
--------------------------------------------------------------------------------
/socket/.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 |
--------------------------------------------------------------------------------
/frontend/.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 |
--------------------------------------------------------------------------------
/frontend/src/requestMethods.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | const LocalBASE_URL="http://localhost:8000/api/";
3 | const BASE_URL = "https://notesharingbackend-ankitkr437.onrender.com/api/";
4 |
5 | export const pf="https://notesharingbackend-ankitkr437.onrender.com/images";
6 |
7 | export const publicRequest = axios.create({
8 | baseURL: BASE_URL,
9 | });
10 |
11 | export const userRequest = axios.create({
12 | baseURL: BASE_URL,
13 | });
--------------------------------------------------------------------------------
/socket/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "socket server for handnote",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "nodemon index.js"
9 | },
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "cors": "^2.8.5",
14 | "express": "^4.17.1",
15 | "nodemon": "^2.0.12",
16 | "socket.io": "^4.1.3"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/backend/model/Commentschema.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const CommentSchema = new mongoose.Schema(
4 | {
5 | userId: {
6 | type: String,
7 | },
8 | noteId:{
9 | type: String,
10 | },
11 | text:{
12 | type:String,
13 | },
14 | likes: {
15 | type: Array,
16 | default: [],
17 | },
18 |
19 | },
20 | { timestamps: true }
21 | );
22 |
23 | const Comment = mongoose.model("Comment", CommentSchema);
24 | export default Comment;
25 |
--------------------------------------------------------------------------------
/frontend/src/component/CircularLoader.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {CircularProgress} from '@material-ui/core';
3 | const Loader = ({item}) => {
4 |
5 | return (
6 |
7 |
8 | {
9 | item!=="redirecting" &&
10 | Fetching the {item}...
11 | }
12 |
13 | )
14 | }
15 |
16 | export default Loader
--------------------------------------------------------------------------------
/backend/database/db.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose';
2 | import dotenv from 'dotenv';
3 | dotenv.config();
4 |
5 | const connection= async (URL)=>{
6 | try {
7 | // const URL='mongodb+srv://ankit:123@cluster0.szlik.mongodb.net/myFirstDatabase?retryWrites=true&w=majority';
8 | await mongoose.connect(URL, { useUnifiedTopology: true, useNewUrlParser: true});
9 | console.log('Database Connected Succesfully');
10 | } catch(error) {
11 | console.log('Error: ', error.message);
12 | }
13 | }
14 | export default connection;
--------------------------------------------------------------------------------
/frontend/README.md:
--------------------------------------------------------------------------------
1 |
2 | # This website is live(better to open in pc)
3 | https://handnote.netlify.app/
4 |
5 | ### Note sharing website integrated with real time chat .
6 | ##### one can upload own notes,see all other available notes and can search for a particular note. can like ,follow,unfollow,comment on any post ,can communicate with any user.
7 |
8 | ### Want to run the project on your local machine:-
9 |
10 | #### Step 1: clone this project
11 | #### Step 2: open terminal and type "npm install"
12 | #### Step 3: type "npm start"
13 | #### Step 4: open "http://localhost:3000/" in new tab
14 |
--------------------------------------------------------------------------------
/frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import {BrowserRouter as Router} from "react-router-dom";
5 | import { Provider } from "react-redux";
6 | import { store, persistor } from "./redux/store";
7 | import { PersistGate } from 'redux-persist/integration/react'
8 | ReactDOM.render(
9 |
10 |
11 |
12 |
13 |
14 |
15 | ,
16 | document.getElementById('root')
17 | );
18 |
19 |
20 |
--------------------------------------------------------------------------------
/frontend/src/loader/Loader.js:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import
3 | {
4 | Card,
5 | CardHeader,
6 | CardContent,
7 | CardMedia,
8 | Avatar,
9 | Typography,
10 | IconButton
11 | } from "@material-ui/core";
12 | import { Skeleton
13 | } from "@material-ui/lab";
14 | import MoreVertIcon from '@material-ui/icons/MoreVert';
15 |
16 |
17 |
18 | function Media() {
19 | const loading=true;
20 |
21 | return (
22 | <>
23 |
24 |
25 |
26 | >
27 | );
28 | }
29 |
30 | export default Media;
31 |
--------------------------------------------------------------------------------
/frontend/src/component/message/Message.jsx:
--------------------------------------------------------------------------------
1 | import "./message.css";
2 | import { format } from "timeago.js";
3 |
4 | export default function Message({ message, own }) {
5 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
6 | return (
7 |
8 |
9 |
14 |
{message.text}
15 |
16 |
{format(message.createdAt)}
17 |
18 | );
19 | }
--------------------------------------------------------------------------------
/frontend/src/pages/searchUserPage/SearchUserPage.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "styled-components";
3 | import { useSelector, useDispatch } from "react-redux";
4 | import { mobile } from "../../responsive"
5 | import BuildConversation from '../../component/BuildConversation/BuildConversation'
6 | import Navbar from "../../component/Navbar";
7 |
8 | const Container = styled.div`
9 | width: 100%;
10 | margin-top: 3vh;
11 | padding: 20px;
12 | `;
13 | const SearchUserPage = () => {
14 | return (
15 | <>
16 |
17 |
18 |
19 |
20 | >
21 | )
22 | }
23 |
24 | export default SearchUserPage
--------------------------------------------------------------------------------
/frontend/src/redux/apiCalls.js:
--------------------------------------------------------------------------------
1 | import {registerFailure, registerStart, registerSuccess, loginFailure, loginStart, loginSuccess } from "./userRedux";
2 | import { publicRequest } from "../requestMethods";
3 |
4 | export const login = async (dispatch, user) => {
5 | dispatch(loginStart());
6 | try {
7 | const res = await publicRequest.post("/auth/login", user);
8 | dispatch(loginSuccess(res.data));
9 | } catch (err) {
10 | dispatch(loginFailure(err));
11 | }
12 | };
13 |
14 | export const register= async (dispatch, user) => {
15 | dispatch(registerStart());
16 | try {
17 | const res = await publicRequest.post("/auth/register", user);
18 | dispatch(registerSuccess(res.data));
19 | } catch (err) {
20 | dispatch(registerFailure());
21 | }
22 | };
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "description": "server for hand notes",
5 | "main": "index.js",
6 | "type": "module",
7 | "scripts": {
8 | "test": "echo \"Error: no test specified\" && exit 1",
9 | "start": "nodemon index.js"
10 | },
11 | "author": "ankit kumar",
12 | "license": "ISC",
13 | "dependencies": {
14 | "axios": "^0.24.0",
15 | "bcrypt": "^5.0.1",
16 | "body-parser": "^1.19.1",
17 | "cors": "^2.8.5",
18 | "dotenv": "^10.0.0",
19 | "express": "^4.17.2",
20 | "express-fileupload": "^1.2.1",
21 | "helmet": "^5.0.1",
22 | "mongoose": "^6.1.5",
23 | "morgan": "^1.10.0",
24 | "multer": "^1.4.5-lts.1",
25 | "nodemon": "^2.0.15",
26 | "path": "^0.12.7"
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/center/Homepost.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useRef } from "react";
2 | import { useState, useEffect } from "react";
3 | import Post from "../../../component/post/Post";
4 | import { publicRequest } from "../../../requestMethods";
5 | const HomePost = ({ x }) => {
6 | const [postuser, setpostuser] = useState(null);
7 |
8 | useEffect(() => {
9 | const fetchuser = async (req, res) => {
10 | try {
11 | const res = await publicRequest.get("users/" +x.userId);
12 | setpostuser(res.data);
13 | } catch (err) {
14 | console.log(err);
15 | }
16 | };
17 | fetchuser();
18 | }, []);
19 |
20 | return (
21 | <>
22 |
23 | >
24 | );
25 | };
26 |
27 | export default HomePost;
28 |
--------------------------------------------------------------------------------
/frontend/src/component/chatOnline/chatOnline.css:
--------------------------------------------------------------------------------
1 | .chatOnlineFriend {
2 | display: flex;
3 | align-items: center;
4 | font-weight: 500;
5 | cursor: pointer;
6 | margin-top: 10px;
7 | }
8 |
9 | .chatOnlineImgContainer {
10 | position: relative;
11 | margin-right: 10px;
12 | }
13 |
14 | .chatOnlineImg {
15 | width: 40px;
16 | height: 40px;
17 | border-radius: 50%;
18 | object-fit: cover;
19 | border: 1px solid white;
20 | }
21 |
22 | .chatOnlineBadge {
23 | width: 10px;
24 | height: 10px;
25 | border-radius: 50%;
26 | background-color: limegreen;
27 | position: absolute;
28 | top: 2px;
29 | right: 2px;
30 | }
31 |
32 | @media screen and (max-width: 768px) {
33 | .chatOnlineName {
34 | display: none;
35 | }
36 | }
--------------------------------------------------------------------------------
/frontend/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
11 |
12 |
18 | NoteSharing
19 |
20 |
21 |
22 | You need to enable JavaScript to run this app.
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/backend/routes/message.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | const router =express.Router();
3 | import Message from '../model/Message.js';
4 |
5 | //add
6 |
7 | router.post("/", async (req, res) => {
8 | const newMessage = new Message(req.body);
9 |
10 | try {
11 | const savedMessage = await newMessage.save();
12 | res.status(200).json(savedMessage);
13 | } catch (err) {
14 | res.status(500).json(err);
15 | }
16 | });
17 |
18 | //get
19 |
20 | router.get("/:conversationId", async (req, res) => {
21 | try {
22 | const messages = await Message.find({
23 | conversationId: req.params.conversationId,
24 | });
25 | res.status(200).json(messages);
26 | } catch (err) {
27 | res.status(500).json(err);
28 | }
29 | });
30 |
31 | export default router
--------------------------------------------------------------------------------
/backend/model/Noteschema.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const NoteSchema = new mongoose.Schema(
4 | {
5 | userId: {
6 | type: String,
7 | required: true,
8 | },
9 | price:{
10 | type:Number
11 | },
12 | notename:{
13 | type: String,
14 | max:15,
15 | },
16 | desc: {
17 | type: String,
18 | max: 500,
19 | },
20 | thumbnailfilename:{
21 | type:String,
22 | },
23 | notefilename:{
24 | type:String,
25 | },
26 | likes: {
27 | type: Array,
28 | default: [],
29 | },
30 | //buy is actually view
31 | buy: {
32 | type: Array,
33 | default: [],
34 | },
35 | },
36 | { timestamps: true }
37 | );
38 |
39 | const Note = mongoose.model("Note", NoteSchema);
40 | export default Note;
41 |
--------------------------------------------------------------------------------
/frontend/src/component/conversations/conversation.css:
--------------------------------------------------------------------------------
1 | .conversation {
2 | display: flex;
3 | align-items: center;
4 | padding: 10px;
5 | cursor: pointer;
6 | margin-top: 20px;
7 | }
8 | .conversation:visited{
9 | background-color: rgb(245, 243, 243);
10 | }
11 | .conversation:hover {
12 | background-color: rgb(245, 243, 243);
13 | }
14 |
15 | .conversationImg {
16 | width: 40px;
17 | height: 40px;
18 | border-radius: 50%;
19 | object-fit: cover;
20 | margin-right: 20px;
21 | }
22 |
23 | .conversationName {
24 | font-weight: 500;
25 | }
26 |
27 | @media screen and (max-width: 768px) {
28 | .conversation{
29 | margin-right: 4px;
30 | flex-direction: column;
31 | }
32 | .conversationName {
33 | text-align: center;
34 | }
35 | .conversationImg{
36 | margin-right: 0;
37 | }
38 | }
--------------------------------------------------------------------------------
/frontend/src/component/message/message.css:
--------------------------------------------------------------------------------
1 | .message {
2 | display: flex;
3 | flex-direction: column;
4 | margin-top: 20px;
5 | word-wrap : break-word;
6 | overflow-wrap: break-word;
7 | }
8 |
9 | .messageTop{
10 | display: flex;
11 | }
12 |
13 | .messageImg {
14 | width: 32px;
15 | height: 32px;
16 | border-radius: 50%;
17 | object-fit: cover;
18 | margin-right: 10px;
19 | }
20 |
21 | .messageText{
22 | padding: 10px;
23 | border-radius: 20px;
24 | background-color: #1877f2;
25 | color: white;
26 | max-width: 300px;
27 | }
28 |
29 | .messageBottom{
30 | font-size: 12px;
31 | margin-top: 10px;
32 | }
33 |
34 | .message.own{
35 | align-items: flex-end;
36 | }
37 |
38 | .message.own .messageText{
39 | background-color: rgb(245, 241, 241);
40 | color: black;
41 | }
--------------------------------------------------------------------------------
/frontend/src/pages/home/Home.css:
--------------------------------------------------------------------------------
1 | .home-container{
2 | padding: 20px 20px;
3 | }
4 | .main{
5 | display: flex;
6 | }
7 | .featured-authors-text{
8 | font-size: 25px;
9 | font-weight: 600;
10 | }
11 | .home-top{
12 | margin-bottom: 2vh;
13 | }
14 | .center-container{
15 | display: flex;
16 | flex-direction: column;
17 | flex: 5;
18 | }
19 | .left-container{
20 | display: flex;
21 | flex-direction: column;
22 | flex: 2;
23 | margin-right: 3vh;
24 | }
25 | .right-container{
26 | display: flex;
27 | flex-direction: column;
28 | flex: 2.5;
29 | margin-left: 3vh;
30 | }
31 | @media only screen and (max-width: 768px) {
32 | .home-container{
33 | padding: 10px 10px;
34 | }
35 | .main{
36 | display: block;
37 | }
38 | .right-container{
39 | display: none;
40 | }
41 | .left-container{
42 | display: none;
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/frontend/src/component/comment/CommentBox.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | .comment-box-container{
8 | display: flex;
9 | flex-direction: row;
10 | margin-top: 2vh;
11 | }
12 |
13 | .comment-box-img{
14 | width: 6vh;
15 | height: 6vh;
16 | box-sizing: border-box;
17 | border: 1px solid rgb(50, 104, 101);
18 | border-radius: 50%;
19 | object-fit: cover;
20 | }
21 |
22 | .comment-box-message{
23 |
24 | width: 100%;
25 | border: 1px solid black;
26 | border-radius: 5px;
27 | background-color: rgb(248, 250, 251);
28 | padding: 7px 10px;
29 | font-size: 12px;
30 |
31 | }
32 | .comment-box-message-name{
33 | display: flex;
34 | flex-direction: column;
35 | margin-left: 1vh;
36 | }
37 | .comment-box-message-name-value{
38 | margin: 0;
39 | font-size: 14px;
40 | font-weight: 600;
41 | color: darkblue;
42 | }
--------------------------------------------------------------------------------
/frontend/src/redux/store.js:
--------------------------------------------------------------------------------
1 | import { configureStore, combineReducers } from "@reduxjs/toolkit";
2 | import userReducer from "./userRedux";
3 | import {
4 | persistStore,
5 | persistReducer,
6 | FLUSH,
7 | REHYDRATE,
8 | PAUSE,
9 | PERSIST,
10 | PURGE,
11 | REGISTER,
12 | } from "redux-persist";
13 | import storage from "redux-persist/lib/storage";
14 |
15 | const persistConfig = {
16 | key: "root",
17 | version: 1,
18 | storage,
19 | };
20 |
21 | const rootReducer = combineReducers({ user: userReducer });
22 |
23 | const persistedReducer = persistReducer(persistConfig, rootReducer);
24 |
25 | export const store = configureStore({
26 | reducer: persistedReducer,
27 | middleware: (getDefaultMiddleware) =>
28 | getDefaultMiddleware({
29 | serializableCheck: {
30 | ignoredActions: [FLUSH, REHYDRATE, PAUSE, PERSIST, PURGE, REGISTER],
31 | },
32 | }),
33 | });
34 |
35 | export let persistor = persistStore(store);
--------------------------------------------------------------------------------
/backend/routes/comment.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | const router =express.Router();
3 |
4 | import User from '../model/Userschema.js';
5 | import Note from '../model/Noteschema.js';
6 | import Comment from '../model/Commentschema.js';
7 |
8 |
9 |
10 | //create a comment for a note
11 | //here id is note id
12 | router.post("/:id", async (req, res) => {
13 | const commentinfo={
14 | userId:req.body.userId,
15 | noteId:req.params.id,
16 | text:req.body.text,
17 | }
18 |
19 | const newComment = new Comment(commentinfo);
20 | try {
21 | const savedComment = await newComment.save();
22 | res.status(200).json(savedComment);
23 | } catch (err) {
24 | res.status(500).json(err);
25 | }
26 | });
27 |
28 |
29 | //for getting all the comment for a note
30 | //here a id is noteid
31 | router.get('/:id', async (req,res)=>{
32 |
33 | try{
34 | const comment =await Comment.find({ noteId: req.params.id });
35 | res.status(200).json(comment);
36 | }catch (err) {
37 | res.status(500).json(err);
38 | }
39 | })
40 |
41 | export default router;
--------------------------------------------------------------------------------
/frontend/src/component/conversations/Conversation.jsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from "react";
2 | import { publicRequest } from "../../requestMethods";
3 | import "./conversation.css";
4 |
5 | export default function Conversation({ conversation, currentUser }) {
6 | const [user, setUser] = useState(null);
7 | const PF ="https://notesharingbackend-ankitkr437.onrender.com/images/"
8 | useEffect(() => {
9 | const friendId = conversation.members.find((m) => m !== currentUser._id);
10 |
11 | const getUser = async () => {
12 | try {
13 | const res = await publicRequest("/users/" + friendId);
14 | setUser(res.data);
15 | } catch (err) {
16 | console.log(err);
17 | }
18 | };
19 | getUser();
20 | }, [currentUser, conversation]);
21 |
22 | return (
23 |
24 |
29 |
{user?.username}
30 |
31 | );
32 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 ANKIT KUMAR
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/backend/model/Userschema.js:
--------------------------------------------------------------------------------
1 | import mongoose from 'mongoose'
2 |
3 | const UserSchema = new mongoose.Schema(
4 | {
5 | username: {
6 | type: String,
7 | require: true,
8 | unique: true,
9 | },
10 | firstname: {
11 | type: String,
12 | },
13 | lastname: {
14 | type: String,
15 | },
16 | interested:{
17 | type: String,
18 | },
19 | email: {
20 | type: String,
21 | required: true,
22 | unique: true,
23 | },
24 | password: {
25 | type: String,
26 | required: true,
27 | },
28 | profilePicture: {
29 | type: String,
30 | default: "",
31 | },
32 | followers: {
33 | type: Array,
34 | default: [],
35 | },
36 | followings: {
37 | type: Array,
38 | default: [],
39 | },
40 | isAdmin: {
41 | type: Boolean,
42 | default: false,
43 | },
44 | institution: {
45 | type: String,
46 | max: 50,
47 | },
48 | notes:{
49 | type:Array,
50 | default:[],
51 | },
52 | },
53 | { timestamps: true }
54 | );
55 |
56 | const User =mongoose.model("User", UserSchema);
57 |
58 | export default User ;
--------------------------------------------------------------------------------
/frontend/src/pages/home/Home.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Topbar from '../../component/topbar/Topbar';
3 | import Author from '../../component/Author/Author.jsx';
4 | import RenderPost from './center/RenderPost.js';
5 | import Homeprofile from './left/Homeprofile.jsx';
6 | import './Home.css';
7 | import UploadNote from '../../component/uploadNote/UploadNote'
8 | import Navbar from '../../component/Navbar';
9 | import Footer from '../../component/footer/Footer'
10 | import BuildConversation from '../../component/BuildConversation/BuildConversation'
11 | const Home = () => {
12 |
13 | return (
14 | <>
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | >
36 | )
37 | }
38 |
39 | export default Home
40 |
--------------------------------------------------------------------------------
/frontend/src/component/comment/CommentBox.js:
--------------------------------------------------------------------------------
1 | import React, {useEffect,useState } from 'react';
2 | import { publicRequest } from '../../requestMethods';
3 | import './CommentBox.css';
4 | import {Link} from "react-router-dom";
5 |
6 | const CommentBox = ({userinfo,text}) => {
7 |
8 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
9 | const [user,setuser]=useState({})
10 | const [isfetchuser,setisfetchuser]=useState(false)
11 | useEffect(()=>{
12 | const fetchuser = async ()=>{
13 | const res= await publicRequest.get(`users/${userinfo}`);
14 | setuser(res.data);
15 | setisfetchuser(true);
16 | }
17 | fetchuser();
18 | },[])
19 |
20 |
21 | return (
22 | <>
23 |
24 |
25 |
26 |
27 |
28 |
{user && user.username}
29 |
30 | {text}
31 |
32 |
33 |
34 | >
35 | );
36 | };
37 |
38 | export default CommentBox;
39 |
40 |
--------------------------------------------------------------------------------
/frontend/src/component/comment/Comment.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | .comment-container{
8 | display: flex;
9 | flex-direction: column;
10 | padding: 1vh 5vw;
11 | }
12 | .comment-info-container{
13 | height: 76vh;
14 | overflow-y: scroll;
15 | padding-right: 2vw;
16 | }
17 | .comment-form{
18 | margin-top: 2vh;
19 | width: 100%;
20 | display: flex;
21 | justify-content: space-between;
22 | box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
23 | }
24 | #submit-comment-form{
25 | display: none;
26 | }
27 | .comment-input{
28 | width: 85%;
29 | padding-left: 10px;
30 | font-size: 14px;
31 | border: none;
32 | }
33 | .comment-submit-icon-form{
34 | width: 15%;
35 | background-color: rgb(51, 125, 228);
36 | color: white;
37 | padding: 12px;
38 | text-align: center;
39 | }
40 |
41 | /* width */
42 | ::-webkit-scrollbar {
43 | width: 5px;
44 | }
45 | ::-webkit-scrollbar-thumb {
46 | background: rgb(148, 149, 151);
47 | border-radius: 10px;
48 | }
49 |
50 |
51 | @media (max-width:600px) {
52 | ::-webkit-scrollbar {
53 | width: 3px;
54 | }
55 | .comment-container{
56 | display: flex;
57 | flex-direction: column;
58 | padding: 1vh 1vw;
59 | }
60 | .comment-info-container{
61 | height: 70vh;
62 | }
63 | .comment-input{
64 | padding-left: 10px;
65 | }
66 | }
--------------------------------------------------------------------------------
/frontend/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { Route,Routes, Switch ,Navigate} from "react-router-dom";
3 | import Login from './pages/login/Login';
4 | import Regiser from './pages/register/Register';
5 | import Home from './pages/home/Home';
6 | import Profile from './pages/profile/Profile';
7 | import UpdateUser from "./component/updateUser/UpdateUser";
8 | import Comment from '../src/component/comment/Comment';
9 | import UpdatePost from "./component/updatepost/UpdatePost";
10 | import Messenger from "./pages/messenger/messenger";
11 | import {useSelector} from 'react-redux'
12 | import SearchUserPage from "./pages/searchUserPage/SearchUserPage";
13 | function App() {
14 | const {currentUser:user}=useSelector((state)=>state.user)
15 |
16 | return (
17 | <>
18 |
19 | : } />
20 | : } />
21 | : } />
22 | : } />
23 | } />
24 | } />
25 | } />
26 | } />
27 | } />
28 |
29 | >
30 | );
31 | }
32 |
33 | export default App;
34 |
--------------------------------------------------------------------------------
/frontend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "frontend",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@material-ui/core": "^4.12.3",
7 | "@material-ui/icons": "^4.11.2",
8 | "@material-ui/lab": "^4.0.0-alpha.61",
9 | "@mui/icons-material": "^5.2.5",
10 | "@reduxjs/toolkit": "^1.9.1",
11 | "@testing-library/jest-dom": "^5.16.1",
12 | "@testing-library/react": "^12.1.2",
13 | "@testing-library/user-event": "^13.5.0",
14 | "axios": "^0.25.0",
15 | "cloudinary-react": "^1.7.1",
16 | "react": "^18.0.0-rc.0-next-fe905f152-20220107",
17 | "react-dom": "^18.0.0-rc.0-next-fe905f152-20220107",
18 | "react-redux": "^8.0.5",
19 | "react-router": "^6.2.1",
20 | "react-router-dom": "^6.2.1",
21 | "react-scripts": "5.0.0",
22 | "redux-persist": "^6.0.0",
23 | "socket.io-client": "^4.5.1",
24 | "styled-components": "^5.3.6",
25 | "timeago.js": "^4.0.2",
26 | "web-vitals": "^3.0.2"
27 | },
28 | "scripts": {
29 | "start": "react-scripts start",
30 | "build": "react-scripts build",
31 | "test": "react-scripts test",
32 | "eject": "react-scripts eject"
33 | },
34 | "eslintConfig": {
35 | "extends": [
36 | "react-app",
37 | "react-app/jest"
38 | ]
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/socket/index.js:
--------------------------------------------------------------------------------
1 | const http = require('http');
2 | const express = require('express');
3 | const cors = require('cors');
4 | const router = require('./router');
5 | const app = express();
6 | const server = http.createServer(app);
7 |
8 | app.use(router);
9 |
10 | const io = require("socket.io")(server,{ cors: { origin: '*' } });
11 |
12 | let users = [];
13 |
14 | const addUser = (userId, socketId) => {
15 | !users.some((user) => user.userId === userId) &&
16 | users.push({ userId, socketId });
17 | console.log(userId+"->"+socketId)
18 | };
19 |
20 | const removeUser = (socketId) => {
21 | users = users.filter((user) => user.socketId !== socketId);
22 | };
23 |
24 | const getUser = (userId) => {
25 | return users.find((user) => user.userId === userId);
26 | };
27 |
28 | io.on("connection", (socket) => {
29 | //when ceonnect
30 | //take userId and socketId from user
31 | socket.on("addUser", (userId) => {
32 | addUser(userId, socket.id);
33 | console.log("a user connected.");
34 | io.emit("getUsers", users);
35 | });
36 |
37 | //send and get message
38 | socket.on("sendMessage", ({ senderId, receiverId, text }) => {
39 | const user = getUser(receiverId);
40 | console.log(text)
41 | io.to(user.socketId).emit("getMessage", {
42 | senderId,
43 | text,
44 | });
45 | });
46 |
47 | //when disconnect
48 | socket.on("disconnect", () => {
49 | console.log("a user disconnected!");
50 | removeUser(socket.id);
51 | io.emit("getUsers", users);
52 | });
53 | });
54 |
55 | server.listen(process.env.PORT || 8900, () => console.log(`Server has started.`));
--------------------------------------------------------------------------------
/backend/routes/auth.js:
--------------------------------------------------------------------------------
1 | //login and registering for a user is done here
2 |
3 | import express from "express";
4 | const router = express.Router();
5 | import User from '../model/Userschema.js';
6 | import bcrypt from 'bcrypt';
7 |
8 | //register
9 | router.post('/register', async (req,res)=>{
10 |
11 | try{
12 | //generate new password
13 | const salt = await bcrypt.genSalt(10);
14 | const hashedPassword = await bcrypt.hash(req.body.password, salt);
15 |
16 | const newuser = new User({
17 | username:req.body.username,
18 | email: req.body.email,
19 | firstname: req.body.firstname,
20 | lastname: req.body.lastname,
21 | password:hashedPassword,
22 | institution:req.body.institution,
23 | desc:req.body.desc,
24 | profilePicture:req.body.profilePicture,
25 |
26 | })
27 |
28 | const user=await newuser.save();
29 | res.status(200).json(user);
30 |
31 | } catch(err){
32 | res.status(500).json(err);
33 | }
34 | })
35 |
36 |
37 |
38 | //Login
39 | router.post("/login", async (req, res) => {
40 | try {
41 | const user = await User.findOne({ email: req.body.email });
42 | !user && res.status(404).json(
43 | {
44 | "error":"user not found",
45 | }
46 | );
47 |
48 | const validPassword = await bcrypt.compare(req.body.password, user.password)
49 | !validPassword && res.status(400).json("wrong password")
50 |
51 | res.status(200).json(user)
52 | } catch (err) {
53 | res.status(500).json(err)
54 | }
55 | });
56 |
57 | export default router;
58 |
--------------------------------------------------------------------------------
/frontend/src/component/TopNavbar/TopNavbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import {
3 | NavbarContainer,
4 | LeftContainer,
5 | RightContainer,
6 | NavbarExtendedContainer,
7 | NavbarInnerContainer,
8 | NavbarLinkContainer,
9 | NavbarLink,
10 | Logo,
11 | OpenLinksButton,
12 | NavbarLinkExtended,
13 | } from "./Navbar.style";
14 | import Homeprofile from "../../pages/home/left/Homeprofile";
15 | import { Link } from "react-router-dom";
16 | import { colors } from "@material-ui/core";
17 |
18 | function Navbar() {
19 | const [extendNavbar, setExtendNavbar] = useState(false);
20 |
21 | return (
22 |
23 |
24 |
25 | {!extendNavbar &&
26 |
27 | NoteSharing
28 |
29 | }
30 |
31 |
32 |
33 | Home
34 | {
36 | setExtendNavbar((curr) => !curr);
37 | }}
38 | >
39 | {extendNavbar ? <>✕> : <> ≡>}
40 |
41 |
42 |
43 |
44 | {extendNavbar && (
45 |
46 |
47 |
48 | )}
49 |
50 | );
51 | }
52 |
53 | export default Navbar;
--------------------------------------------------------------------------------
/frontend/src/redux/userRedux.js:
--------------------------------------------------------------------------------
1 | import { createSlice } from "@reduxjs/toolkit";
2 |
3 | const userSlice = createSlice({
4 | name: "user",
5 | initialState: {
6 | currentUser: null,
7 | isFetching: false,
8 | error: false,
9 | searchedValue:null,
10 | },
11 | reducers: {
12 | loginStart: (state) => {
13 | state.isFetching = true;
14 | },
15 | loginSuccess: (state, action) => {
16 | state.isFetching = false;
17 | state.currentUser = action.payload;
18 | state.error=false;
19 | },
20 | loginFailure: (state,action) => {
21 | state.isFetching = false;
22 | state.error = true;
23 | },
24 | registerStart: (state) => {
25 | state.isFetching = true;
26 | },
27 | registerSuccess: (state, action) => {
28 | state.isFetching = false;
29 | state.currentUser = action.payload;
30 | state.error=false;
31 | },
32 | registerFailure: (state) => {
33 | state.isFetching = false;
34 | state.error = true;
35 | },
36 | logout: (state) => {
37 | state.currentUser=null;
38 | },
39 | search:(state,action)=>{
40 | state.searchedValue=action.payload;
41 | },
42 | follow:(state,action)=>{
43 | state.currentUser.followings=[...state.currentUser.followings, action.payload]
44 | },
45 | unFollow:(state,action)=>{
46 |
47 | state.currentUser.followings= state.currentUser.followings.filter(
48 | (following) => following !== action.payload);
49 |
50 | }
51 | },
52 | });
53 |
54 | export const { registerStart, registerSuccess, registerFailure,loginStart, loginSuccess, loginFailure,logout,search,follow,unFollow} = userSlice.actions;
55 | export default userSlice.reducer;
--------------------------------------------------------------------------------
/backend/routes/conversation.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | const router =express.Router();
3 | import Conversation from '../model/Conversation.js';
4 |
5 | router.post("/", async (req, res) => {
6 | if(req.body.senderId===req.body.receiverId){
7 | res.status(200).json("You can not chat with yourself");
8 | }
9 | else{
10 | const newConversation = new Conversation({
11 | members: [req.body.senderId, req.body.receiverId],
12 | });
13 |
14 | try {
15 | const conversation = await Conversation.find({
16 | members: { $all: [req.body.senderId, req.body.receiverId] },
17 | });
18 | if(!conversation.length){
19 | const savedConversation = await newConversation.save();
20 | res.status(200).json(savedConversation);
21 | }
22 | else{
23 | res.status(200).json(conversation);
24 | }
25 | } catch (err) {
26 | res.status(500).json(err);
27 | }
28 | }
29 | });
30 |
31 | //get conversation of a pair
32 |
33 | router.get("/:senderId/:senderId", async (req, res) => {
34 | try {
35 | const conversation = await Conversation.find({
36 | members: { $in: [req.params.senderId,req.params.receiverId] },
37 | });
38 | res.status(200).json(conversation);
39 | } catch (err) {
40 | res.status(500).json(err);
41 | }
42 | });
43 |
44 | //get conv of a user
45 |
46 | router.get("/:userId", async (req, res) => {
47 | try {
48 | const conversation = await Conversation.find({
49 | members: { $in: [req.params.userId] },
50 | });
51 | res.status(200).json(conversation);
52 | } catch (err) {
53 | res.status(500).json(err);
54 | }
55 | });
56 |
57 |
58 |
59 |
60 |
61 |
62 | export default router ;
63 |
--------------------------------------------------------------------------------
/frontend/src/component/chatOnline/chatOnline.jsx:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 | import { useEffect, useState } from "react";
3 | import { publicRequest } from "../../requestMethods";
4 | import "./chatOnline.css";
5 |
6 | export default function ChatOnline({ onlineUsers, currentId, setCurrentChat }) {
7 | const [friends, setFriends] = useState([]);
8 | const [onlineFriends, setOnlineFriends] = useState([]);
9 | const PF="https://notesharingbackend-ankitkr437.onrender.com/images/";
10 |
11 | useEffect(() => {
12 | const getFriends = async () => {
13 | const res = await publicRequest.get("/users");
14 | setFriends(res.data);
15 | };
16 |
17 | getFriends();
18 | }, [currentId]);
19 | console.log(onlineUsers)
20 | useEffect(() => {
21 | setOnlineFriends(friends.filter((f) => onlineUsers.includes(f._id)));
22 | }, [friends, onlineUsers]);
23 |
24 | const handleClick = async (user) => {
25 | try {
26 | const res = await axios.get(
27 | `/conversations/find/${currentId}/${user._id}`
28 | );
29 | setCurrentChat(res.data);
30 | } catch (err) {
31 | console.log(err);
32 | }
33 | };
34 |
35 | return (
36 |
37 | {onlineFriends.map((o) => (
38 |
handleClick(o)}>
39 |
40 |
49 |
50 |
51 |
{o?.username}
52 |
53 | ))}
54 |
55 | );
56 | }
--------------------------------------------------------------------------------
/frontend/src/component/TopNavbar/Navbar.style.js:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { Link } from "react-router-dom";
3 |
4 | export const NavbarContainer = styled.nav`
5 | width: 100%;
6 | height: ${(props) => (props.extendNavbar ? "100vh" : "60px")};
7 | background-color: #3E8DE3;
8 | display: flex;
9 | flex-direction: column;
10 |
11 | @media (min-width: 700px) {
12 | height: 60px;
13 | }
14 | `;
15 |
16 | export const LeftContainer = styled.div`
17 | flex: 70%;
18 | display: flex;
19 | align-items: center;
20 | padding-left: 1%;
21 | `;
22 |
23 | export const RightContainer = styled.div`
24 | flex: 30%;
25 | display: flex;
26 | justify-content: flex-end;
27 | padding-right: 5px;
28 | `;
29 |
30 | export const NavbarInnerContainer = styled.div`
31 | width: 100%;
32 | height: 60px;
33 | display: flex;
34 | `;
35 |
36 | export const NavbarLinkContainer = styled.div`
37 | display: flex;
38 | `;
39 |
40 | export const NavbarLink = styled(Link)`
41 | color: white;
42 | font-size: x-large;
43 | text-decoration: none;
44 | margin: 10px;
45 | @media (max-width: 700px) {
46 | display: none;
47 | }
48 | `;
49 |
50 | export const NavbarLinkExtended = styled(Link)`
51 | color: white;
52 | font-size: x-large;
53 | text-decoration: none;
54 | margin: 10px;
55 | `;
56 |
57 | export const Logo = styled.h2`
58 | margin-left: 10px;
59 | max-width: 180px;
60 | color: white;
61 | height: auto;
62 | cursor: pointer;
63 | `;
64 |
65 | export const OpenLinksButton = styled.button`
66 | width: 70px;
67 | height:45px;
68 | background: none;
69 | border: none;
70 | color: white;
71 | font-size: 45px;
72 | cursor: pointer;
73 | @media (min-width: 700px) {
74 | display: none;
75 | }
76 | `;
77 |
78 | export const NavbarExtendedContainer = styled.div`
79 | display: flex;
80 | flex-direction: column;
81 | align-items: center;
82 | @media (min-width: 700px) {
83 | display: none;
84 | }
85 | `;
--------------------------------------------------------------------------------
/frontend/src/component/updatepost/UpdatePost.css:
--------------------------------------------------------------------------------
1 | *{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 | .Update-post-container-complete{
7 | height: 100vh;
8 | width: 96vw;
9 | padding-top: 7vh;
10 | padding-left: 3vw;
11 | }
12 | .Update-post-container{
13 | display: flex;
14 | flex-direction: column;
15 | box-shadow: 0 6px 13px rgb(232 205 205);
16 | font-size: 0;
17 | height: 69vh;
18 | padding-left: 4vh;
19 | }
20 |
21 | .Update-post-container-name{
22 |
23 | font-size: 24px;
24 | font-weight: 600;
25 | text-align: center;
26 | margin-bottom: 4vh;
27 | color: darkgray;
28 | }
29 |
30 |
31 | .Update-post-container-form{
32 | display: flex;
33 | flex-direction: column;
34 | }
35 |
36 | .Update-post-input-box{
37 | height: 12vh;
38 | display: flex;
39 | flex-direction: column;
40 | }
41 |
42 | .Update-post-input-heading{
43 | font-size: 15px;
44 | margin-bottom: 1vh;
45 | }
46 |
47 | .Update-post-input-block{
48 | height: 6vh;
49 | width: 90%;
50 | font-size: 15px;
51 | border: 1px solid grey;
52 | padding: 2vh;
53 | }
54 | .Update-post-input-box-file{
55 | height: 13vh;
56 | display: flex;
57 | flex-direction: column;
58 | }
59 |
60 | .Update-post-input-heading-file{
61 | font-size: 15px;
62 | margin-bottom: 1vh;
63 | }
64 |
65 | .Update-post-input-block-file{
66 | height: 7vh;
67 | width: 90%;
68 | font-size: 14px;
69 | border: none;
70 | outline: none;
71 | }
72 | .Update-post-input-block-file:active{
73 | border: none;
74 | outline: none;
75 | }
76 | .Update-post-container-form-submit{
77 | background-color: black;
78 | font-size: 16px;
79 | padding: 7px;
80 | width: 17%;
81 | color: white;
82 | border: 1px solid black;
83 | }
84 |
85 | @media only screen and (max-width: 650px) {
86 | .Update-post-container-name{
87 | margin-right: 3vh;
88 | }
89 | .Update-post-container-form-submit{
90 | font-size: 14px;
91 | width: 40%;
92 | }
93 | }
--------------------------------------------------------------------------------
/backend/index.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | import mongoose from 'mongoose';
3 | import dotenv from 'dotenv';
4 | import connection from './database/db.js';
5 | import morgan from 'morgan';
6 | import helmet from 'helmet';
7 | import multer from 'multer';
8 | import path from 'path';
9 |
10 | import useRoute from './routes/users.js';
11 | import authRoute from './routes/auth.js';
12 | import noteroute from './routes/notes.js';
13 | import commentroute from './routes/comment.js'
14 | import conversationroute from './routes/conversation.js'
15 | import messageroute from './routes/message.js'
16 |
17 | import cors from 'cors';
18 | const app=express();
19 | dotenv.config();
20 |
21 | const port=process.env.PORT ||8000;
22 |
23 | const URL=process.env.URL;
24 |
25 | connection(URL);
26 |
27 |
28 | // const seturl="http://localhost:3000";
29 | // const seturl2="https://handnote.netlify.app/"
30 |
31 | app.use(cors({
32 | origin:"*",
33 | methods: ['GET','POST','DELETE','UPDATE','PUT'],
34 | allowedHeaders:['Content-Type', 'Authorization','sessionId'],
35 | exposedHeaders:['sessionId'],
36 | preflightContinue:false
37 | }));
38 | // app.use(function(req, res, next) {
39 | // res.header("Access-Control-Allow-Origin", "*");
40 | // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
41 | // next();
42 | // });
43 | app.use(express.json());
44 | app.use(helmet());
45 | app.use(morgan("common"));
46 |
47 | const __dirname = path.resolve();
48 | app.use("/images", express.static(path.join(__dirname, "public/images"), {
49 | setHeaders: function(res, path) {
50 | res.set("Cross-Origin-Resource-Policy","cross-origin");
51 | }
52 | }));
53 |
54 | app.use('/api/users',useRoute);
55 | app.use('/api/auth',authRoute);
56 | app.use('/api/notes',noteroute);
57 | app.use('/api/comments',commentroute);
58 | app.use('/api/conversations',conversationroute);
59 | app.use('/api/messages',messageroute);
60 |
61 |
62 | app.get("/",(req,res)=>{
63 | res.send("welcome to home page");
64 | })
65 | app.listen(port,()=>console.log(`listening on port at ${port}`));
--------------------------------------------------------------------------------
/frontend/src/component/footer/Footer.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./Footer.css";
3 | import { Link } from "react-router-dom";
4 | import { useSelector } from "react-redux";
5 | const Footer = () => {
6 | const currentUser= useSelector(state=>state.user.currentUser)
7 | return (
8 | <>
9 |
10 |
11 |
12 |
13 | NoteSharing
14 |
15 |
16 |
17 |
ABOUT US
18 |
19 | A website which allows to get any desired notes.
20 |
21 | Users can upload own notes or view/search for any notes, can create own awesome profile or can chat with any other users
22 |
23 |
24 |
25 |
29 |
30 |
31 |
32 |
33 | Copyright © 2023 NoteSharing. All Rights Reserved
34 |
35 |
36 |
37 | Home
38 |
39 |
40 | Profile
41 |
42 |
43 | Chat
44 |
45 |
46 |
47 |
48 | >
49 | );
50 | };
51 |
52 | export default Footer;
53 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/left/HomeProfile.css:
--------------------------------------------------------------------------------
1 | .leftmost-container{
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | border: 1px solid darkcyan;
6 | border-radius:20px;
7 | height: 75vh;
8 | }
9 | .menu-username{
10 | color: white;
11 | margin-top: 2vh;
12 | }
13 | .leftmost-topbar{
14 | display: flex;
15 | border-radius: 20px;
16 | padding-top: 2vh;
17 | flex-direction: column;
18 | align-items: center;
19 | height: 20vh;
20 | background-color: #3E8DE3;
21 | }
22 | .leftmost-topbar Link img{
23 | height: 50px;
24 | width: 50px;
25 | border: 2px solid cornflowerblue;
26 | object-fit: cover;
27 | border-radius: 50%;
28 | margin-right: -3vw;
29 | }
30 | .leftmost-topbar Link p{
31 | font-size: 25px;
32 | font-weight: 600;
33 | }
34 |
35 | .menuItem{
36 | display: flex;
37 | justify-content: center;
38 | margin-top: 1vh;
39 | margin-bottom: 1vh;
40 | }
41 | .leftmost-links{
42 | font-size: 17px;
43 | font-weight: 600;
44 | color: black;
45 | }
46 | .contact-text{
47 | display: flex;
48 | align-items: center;
49 | }
50 | .footer-home-container{
51 | display: flex;
52 | flex-direction: column;
53 | font-size: 14px;
54 | align-items: center;
55 | margin-top: 5vh;
56 | }
57 | .contact-upper p{
58 | text-align: center;
59 | color: black;
60 | }
61 |
62 | .logout{
63 | margin-left: 0;
64 | display: flex;
65 | justify-content: center;
66 | }
67 | .leftmost-desc{
68 | display: flex;
69 | flex-direction: column;
70 | align-items: start;
71 | }
72 |
73 | @media only screen and (max-width: 768px) {
74 | .leftmost-topbar{
75 | width: 30vh;
76 | }
77 | .menuItem{
78 | margin-top: 2vh;
79 | margin-bottom: 1vh;
80 | }
81 | .contact-upper p{
82 | text-align: center;
83 | margin-top: 1vh;
84 | font-size: 15px;
85 | margin-bottom: 1vh;
86 | }
87 | .contact-text a{
88 | color: black;
89 | margin-top: 2vh;
90 | margin-left: 1vh;
91 | margin-right: 1vh;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/frontend/src/pages/messenger/messenger.css:
--------------------------------------------------------------------------------
1 | .messenger {
2 | height: calc(100vh - 20vh);
3 | display: flex;
4 | }
5 |
6 | .chatMenu {
7 | flex: 3.5;
8 | }
9 |
10 | .chatMenuInput {
11 | width: 90%;
12 | padding: 10px 0;
13 | border: none;
14 | outline: none;
15 | font-size: 20px;
16 | border-bottom: 1px solid gray;
17 | }
18 |
19 | .chatBox {
20 | flex: 5.5;
21 | }
22 |
23 | .chatBoxWrapper {
24 | display: flex;
25 | flex-direction: column;
26 | justify-content: space-between;
27 | position: relative;
28 | }
29 |
30 | .chatBoxTop {
31 | height: 100%;
32 | overflow-y: scroll;
33 | padding-right: 10px;
34 | }
35 |
36 | .chatBoxBottom {
37 | margin-top: 5px;
38 | display: flex;
39 | align-items: center;
40 | justify-content: space-between;
41 | box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px;
42 | }
43 |
44 | .chatMessageInput {
45 | width: 85%;
46 | height: 45px;
47 | padding: 10px;
48 | border: none;
49 | }
50 |
51 | .chatSubmitButton {
52 | width: 15%;
53 | height: 45px;
54 | border: none;
55 | cursor: pointer;
56 | background-color: #3E8DE3;
57 | color: white;
58 |
59 | }
60 |
61 | .chatOnline {
62 | flex: 3;
63 | }
64 |
65 | .chatMenuWrapper,
66 | .chatBoxWrapper,
67 | .chatOnlineWrapper {
68 | padding: 10px;
69 | height: 100%;
70 | }
71 |
72 | .noConversationText {
73 | position: absolute;
74 | top: 10%;
75 | font-size: 50px;
76 | color: rgb(224, 220, 220);
77 | cursor: default;
78 | }
79 |
80 | @media screen and (max-width: 768px) {
81 | .messenger{
82 | height: calc(100vh - 21vh);
83 | }
84 | .chatMenu {
85 | flex: 1;
86 | }
87 |
88 | .chatMenuInput {
89 | display: none;
90 | }
91 |
92 | .chatBox{
93 | flex: 10;
94 | }
95 | .chatMenuWrapper{
96 | padding: 0;
97 | }
98 | .chatOnline{
99 | display: none;
100 | flex: 1px;
101 | }
102 | .chatMessageInput{
103 | height: 45px;
104 | }
105 | }
--------------------------------------------------------------------------------
/frontend/src/component/banner/Banner.css:
--------------------------------------------------------------------------------
1 | *{
2 | padding: 0;
3 | margin: 0;
4 | box-sizing: border-box;
5 | }
6 | .banner-container{
7 | width: 100%;
8 | display: flex;
9 | justify-content: center;
10 | height: 27vh;
11 | padding: 1vh 2vh;
12 | }
13 | .banner-first{
14 | display: flex;
15 | flex: 3;
16 | height: 100%;
17 | text-align: center;
18 | justify-content:space-around;
19 | align-items: center;
20 | padding: 0 20vh;
21 | }
22 | .banner-image-container{
23 | flex: 2;
24 | display: flex;
25 | text-align: center;
26 | justify-content: center;
27 | align-items: center;
28 | }
29 | .banner-image{
30 | width: 23vh;
31 | height: 23vh;
32 | border-radius: 50%;
33 | object-fit: cover;
34 |
35 | }
36 | .carousel .slide img {
37 | border: 2px solid rgb(67, 94, 143);
38 | }
39 |
40 | .banner-text{
41 | flex: 3;
42 | }
43 | .carousel .slide img {
44 | width: 23vh;
45 | height: 23vh;
46 | }
47 | .banner-name{
48 | font-weight: 600;
49 | font-size: 28px;
50 | cursor: pointer;
51 | color: rgb(22, 9, 78);
52 | }
53 | .banner-name:hover{
54 | color: rgb(106, 138, 228);
55 | }
56 | .banner-sell{
57 | font-weight: 300;
58 | font-size: 23px;
59 | color: rgb(23, 14, 100);
60 | }
61 | .carousel-container {
62 | background-image: linear-gradient(to right, rgb(218 221 230), rgb(214 97 97));
63 | margin-left: 3vw;
64 | margin-right: 2vw;
65 | box-shadow: 0px 1px 3px rgb(32, 27, 41);
66 | }
67 |
68 | .carousel.carousel-slider .control-arrow {
69 | background-color: rgb(10, 32, 49);
70 | height: 9vh;
71 | margin-top: 9vh;
72 | }
73 |
74 |
75 | .banner-notesname:hover{
76 | color: rgb(36, 44, 8);
77 | }
78 |
79 | @media only screen and (max-width: 750px) {
80 |
81 |
82 | .carousel.carousel-slider .control-arrow {
83 | padding: 5;
84 | }
85 | .banner-sell{
86 | font-size: 14px;
87 | }
88 | .banner-name{
89 | font-size: 21px;
90 | }
91 | .banner-image-container{
92 | flex: 3;
93 | }
94 |
95 | .carousel .slide img {
96 | width: 16vh;
97 | height: 16vh;
98 | }
99 |
100 | .banner-first{
101 | padding: 0 4vh;
102 | }
103 | }
--------------------------------------------------------------------------------
/frontend/src/pages/home/left/Homeprofile.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useRef } from "react";
2 | import "./HomeProfile.css";
3 | import { Link } from "react-router-dom";
4 | import { useState, useEffect } from "react";
5 | import Media from '../../../loader/Loader.js'
6 | import '../../../component/topbar/Topbar.css'
7 | import {useSelector} from 'react-redux';
8 | import { Chat,AccountCircle, ExitToApp,Settings,Home} from "@material-ui/icons";
9 | const Homeprofile = () => {
10 |
11 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
12 |
13 | const {currentUser,isFetching} = useSelector((state)=>state.user)
14 | const user=currentUser
15 |
16 | const logouthandler=()=>{
17 | console.log("logout")
18 | localStorage.clear();
19 | window.location.reload();
20 | }
21 | if(isFetching){
22 | return
23 | }
24 |
25 | return (
26 | <>
27 |
28 |
29 |
30 |
31 |
{user?.username}
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
View Profile
48 |
49 |
50 |
51 |
55 |
56 |
57 |
61 |
62 |
66 |
67 |
68 | >
69 | )
70 | }
71 |
72 | export default Homeprofile
--------------------------------------------------------------------------------
/frontend/src/component/Author/Author.css:
--------------------------------------------------------------------------------
1 | .author-container{
2 | display: flex;
3 | overflow-x: auto;
4 | padding: 2vh 1vh;
5 | }
6 | .author-container::-webkit-scrollbar {
7 | display: none;
8 | }
9 |
10 | .author-container {
11 | -ms-overflow-style: none;
12 | scrollbar-width: none;
13 | }
14 |
15 | .author-card{
16 | min-width: 170px;
17 | min-height: 180px;
18 | box-shadow: 0px 0px 10px 7px rgb(233, 238, 233);
19 | border-radius: 8px;
20 | margin-left: 1vh;
21 | margin-right: 1vh;
22 | display: flex;
23 | flex-direction: column;
24 | align-items: center;
25 | padding-top: 1vh;
26 | }
27 | .author-image{
28 | height: 60px;
29 | width: 60px;
30 | object-fit: cover;
31 | border-radius: 50%;
32 | border: 2px solid cornflowerblue;
33 | }
34 | .author-name{
35 | font-size: 16px;
36 | font-weight: 600;
37 | }
38 | .featured-author{
39 | font-size: 27px;
40 | font-weight: 200;
41 | }
42 | .author-notes-followers-container{
43 | display: flex;
44 | }
45 | .author-notes-followers{
46 | display: flex;
47 | flex-direction: column;
48 | align-items: center;
49 | width:75px;
50 | }
51 | .author-notes-followers-count{
52 | font-size: 18px;
53 | color: cornflowerblue;
54 | }
55 | .author-notes-followers-text{
56 | font-size: 13px;
57 | font-weight: 300;
58 | }
59 | .seperation-image{
60 | width: 20px;
61 |
62 | }
63 |
64 | .author-institution{
65 | margin-top: 3vh;
66 | font-size: 14px;
67 | font-weight: 500;
68 | }
69 |
70 |
71 | @media only screen and (max-width: 600px) {
72 | .user-timeline {
73 | padding-left: 0vw;
74 | }
75 | .profile-top{
76 | flex-direction: column;
77 | }
78 | .featured-author{
79 | font-size: 24px;
80 | }
81 | .author-container{
82 | width: 100%;
83 | margin-top: 0vh;
84 | padding: 2vh 0vh;
85 | }
86 | .author-card{
87 | min-width: 135px;
88 | min-height: 135px;
89 | }
90 | .author-image{
91 | height: 45px;
92 | width: 45px;
93 | object-fit: cover;
94 | border-radius: 50%;
95 | border: 2px solid cornflowerblue;
96 | }
97 | .author-name{
98 | font-size: 14px;
99 | font-weight: 600;
100 | }
101 |
102 | .author-notes-followers-container{
103 | display: flex;
104 | }
105 | .author-notes-followers{
106 | display: flex;
107 | flex-direction: column;
108 | align-items: center;
109 | width:64px;
110 | }
111 | .author-notes-followers-count{
112 | font-size: 16px;
113 | color: cornflowerblue;
114 | }
115 | .author-notes-followers-text{
116 | font-size: 11px;
117 | font-weight: 300;
118 | }
119 | .seperation-image{
120 | width: 0px;
121 |
122 | }
123 |
124 | }
--------------------------------------------------------------------------------
/frontend/src/component/SearchedUser/SearchedUser.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "styled-components";
3 | import { useState,useEffect} from "react";
4 | import { useSelector, useDispatch } from "react-redux";
5 | import { mobile } from "../../responsive"
6 | import { publicRequest } from '../../requestMethods'
7 | import {Send} from "@material-ui/icons";
8 | import { makeStyles } from "@material-ui/core/styles";
9 | import { Navigate, useNavigate } from "react-router";
10 | import Loader from "../CircularLoader";
11 | const UserOne=styled.div`
12 | width: 100%;
13 | background-color:#99c9f9;
14 | height: 12vh;
15 | border-radius: 10px;
16 | padding: 8px;
17 | display: flex;
18 | margin-bottom: 2vh;
19 | cursor: pointer;
20 | `
21 | const UserLeft=styled.div`
22 | display: flex;
23 | justify-content: start;
24 | align-items: center;
25 | width: 70%;
26 | `
27 | const UserRight=styled.div`
28 | display: flex;
29 | justify-content: end;
30 | align-items: center;
31 | padding-right: 8px;
32 | width: 30%;
33 | `
34 | const UserImg=styled.img`
35 | height: 44px;
36 | width: 44px;
37 | border-radius: 50%;
38 | object-fit: cover;
39 | `
40 | const UserName=styled.div`
41 | margin-left: 5px;
42 | font-size: 17px;
43 | `
44 | const useStyles = makeStyles(theme => ({
45 | sendIcon: {
46 | color:"#2a6bb0",
47 | fontSize:"2.5rem",
48 | }
49 | }));
50 |
51 | const SearchedUser = ({receiverUser}) => {
52 | // console.log(receiverUser)
53 | const pf = "https://notesharingbackend-ankitkr437.onrender.com/images/";
54 | const { currentUser:user} = useSelector((state) => state.user);
55 | const classes =useStyles();
56 | const [isbuilding ,setisbuilding] =useState(false)
57 | const [receiverId,setreceiverId]=useState(receiverUser?._id)
58 | const navigate=useNavigate();
59 | const buildConversationHandler= async({u})=>{
60 | console.log({ senderId:user?._id,
61 | receiverId})
62 | setisbuilding(true)
63 | try{
64 | const res= await publicRequest.post("conversations",{
65 | senderId:user?._id,
66 | receiverId
67 | })
68 | console.log(res.data)
69 | setisbuilding(false)
70 | navigate('/messenger')
71 | }
72 | catch(err){
73 | console.log(err);
74 | }
75 | }
76 | return (
77 | <>
78 | {
79 | isbuilding?:
80 |
81 |
82 |
87 | {receiverUser?.username}
88 |
89 |
90 |
91 |
92 |
93 | }
94 | >
95 | )
96 | }
97 |
98 | export default SearchedUser
--------------------------------------------------------------------------------
/frontend/src/component/comment/Comment.js:
--------------------------------------------------------------------------------
1 | import React, {useRef} from 'react';
2 | import './Comment.css';
3 | import {useParams } from "react-router-dom";
4 | import { useState, useEffect } from "react";
5 | import CommentBox from './CommentBox';
6 | import {publicRequest} from '../../requestMethods'
7 | import Loader from '../../loader/Loader';
8 | import {useSelector} from 'react-redux'
9 | import {
10 | ArrowForward,
11 | } from "@material-ui/icons";
12 | import Navbar from '../Navbar';
13 | const Comment = () => {
14 |
15 | const {currentUser:user}=useSelector((state)=>state.user)
16 | const {notesid}=useParams();
17 | const [commenttext,setcommenttext] =useState();
18 | const [allcomment,setallcomment] =useState([]);
19 | const [isfetchcomment,setisfetchcomment] =useState(false);
20 | const takedown=useRef();
21 |
22 | useEffect(()=>{
23 | const fetchComment =async(req,res)=>{
24 | try{
25 | const res = await publicRequest.get("comments/" + notesid)
26 | setallcomment(res.data)
27 | setisfetchcomment(true);
28 | }
29 | catch(err){
30 | console.log(err);
31 | }
32 | }
33 | fetchComment();
34 | },[notesid])
35 |
36 | useEffect(()=>{
37 | takedown.current?.scrollIntoView({behavior:"smooth"})
38 | },[allcomment,notesid])
39 |
40 | const CommentHandler = async(e)=>{
41 | e.preventDefault();
42 | try {
43 | const res= await publicRequest.post("comments/" + notesid, {
44 | userId:user._id,
45 | text:commenttext,
46 | });
47 | setallcomment([...allcomment,res.data])
48 | setcommenttext("")
49 | } catch (err) {console.log(err)}
50 | }
51 |
52 |
53 | return <>
54 |
55 |
56 |
57 |
58 | {
59 | isfetchcomment?allcomment.map((x,i)=>{
60 | return(
61 |
62 |
63 |
64 | )
65 | })
66 | :
67 | }
68 |
69 |
86 |
87 | >;
88 | };
89 |
90 | export default Comment;
91 |
--------------------------------------------------------------------------------
/frontend/src/component/footer/Footer.css:
--------------------------------------------------------------------------------
1 | .footer-container{
2 | display: flex;
3 | flex-direction: column;
4 | background-color: rgb(43, 84, 159);
5 | height: 32vh;
6 | width: 100%;
7 | justify-content: center;
8 | align-items: center;
9 | /* padding-left: 3vw;
10 | padding-right: 3vw;
11 | padding-top: 3vh;
12 | padding-bottom: 3vh; */
13 | }
14 | .logo{
15 | font-size: 32px;
16 | font-weight: 800;
17 | margin: 0;
18 | padding: 0;
19 | color:white;
20 | }
21 | .about-footer{
22 | display: flex;
23 | flex-direction: row;
24 | margin-bottom: 5vh;
25 | width: 85%;
26 | justify-content: space-between;
27 | }
28 | .footer-bottom-container{
29 | display: flex;
30 | width: 85%;
31 | /* height: 6vh; */
32 | /* background-color: rgb(29, 64, 130); */
33 | flex-direction: row;
34 | justify-content: space-between;
35 | align-items: center;
36 | }
37 | .crypto-logo{
38 | margin-right: 1vw;
39 | font-size: 35px;
40 | color: white;
41 | }
42 | .about-content-container{
43 | width: 40%;
44 | }
45 | .about-us-title{
46 | font-size: 20px;
47 | font-weight: 600;
48 | color: white;
49 | margin-bottom: 1vh;
50 | }
51 | .about-content{
52 | font-size: 13px;
53 | font-weight: 300;
54 | color: rgb(187, 196, 196);
55 | }
56 | .copyright{
57 | color: rgb(255, 255, 255);
58 | }
59 | .footer-link{
60 | display: flex;
61 | }
62 | .footer-link-item{
63 | color: white;
64 | margin-left: 3vw;
65 | margin-left: 3vw;
66 | }
67 | .footer-link-item:hover{
68 | color: rgb(90, 147, 222);
69 | }
70 | .Contact-contribute-container{
71 | display: flex;
72 | flex-direction: column;
73 | }
74 | .Contact-contribute-container a{
75 | font-size: 15px;
76 | font-weight: 400;
77 | }
78 | @media (max-width:700px) {
79 | .footer-container{
80 | height: 41vh;
81 | }
82 | .about-footer{
83 | flex-direction: column;
84 | justify-content: center;
85 | align-items: center;
86 | }
87 | .about-content-container{
88 | text-align: center;
89 | }
90 | .footer-bottom-container{
91 | width: 100%;
92 | flex-direction:column-reverse;
93 | justify-content: center;
94 | align-items: center;
95 | margin-top: -3vh;
96 | }
97 | .copyright{
98 | font-size: 14px;
99 | font-weight: 400;
100 | margin-top: 2vh;
101 | }
102 | .crypto-logo{
103 | width: 100%;
104 | margin-right: 0;
105 | margin-bottom: 2vh;
106 | text-align: center;
107 | }
108 | .about-content-container{
109 | width: 100%;
110 | }
111 | .footer-link{
112 | /* flex-direction: column; */
113 | width: 100%;
114 | justify-content: space-around;
115 | text-align: center;
116 | }
117 | .footer-link-item{
118 | margin-bottom: 1vh;
119 | }
120 | .Contact-contribute-container{
121 | flex-direction: row;
122 | justify-content: space-evenly;
123 | width: 100%;
124 | margin-top: 2vh;
125 | }
126 |
127 | }
--------------------------------------------------------------------------------
/frontend/src/component/Author/Author.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, createContext } from "react";
2 | import "./Author.css";
3 | import { Link } from "react-router-dom";
4 | import { useState, useEffect } from "react";
5 | import {publicRequest} from '../../requestMethods'
6 | import CircularLoader from '../CircularLoader'
7 | const Author = () => {
8 | const pf = "https://notesharingbackend-ankitkr437.onrender.com/images/";
9 | const [authors, setauthors] = useState([]);
10 | const [isauthors, setisauthors] = useState(false);
11 | const TotalPublishNotes = createContext();
12 | useEffect(() => {
13 | const fetchAllFeaturedAuthor = async () => {
14 | const res = await publicRequest.get("users/stats/authors");
15 | setauthors(res.data);
16 | setisauthors(true);
17 | };
18 | fetchAllFeaturedAuthor();
19 | }, []);
20 |
21 |
22 | return (
23 | <>
24 |
25 | Featured Authors
26 | {!(isauthors)?
27 | :
28 |
29 | {isauthors &&
30 | authors.map((author, i) => {
31 |
32 | return (
33 |
34 |
35 |
39 |
47 |
48 | { author.username }
49 |
50 |
51 |
52 |
53 |
54 | {author.notes_length}
55 |
56 |
Notes
57 |
58 |
59 |
60 |
61 | {
62 | author.followers_length
63 | }
64 |
65 |
Followers
66 |
67 |
68 | {/* {author.institution &&
69 |
{author.institution}
70 | } */}
71 |
72 |
73 | );
74 |
75 | })}
76 |
77 | }
78 | >
79 | );
80 | };
81 |
82 | export default Author;
83 |
--------------------------------------------------------------------------------
/frontend/src/component/uploadNote/UploadNote.css:
--------------------------------------------------------------------------------
1 | .uploadNote-container{
2 | margin:0;
3 | padding:0;
4 | box-sizing: border-box;
5 | }
6 | .uploadNote-container-top{
7 | display: flex;
8 | height: 8vh;
9 | }
10 | .uploadNote-img{
11 | border: 1px solid #2a78cb;
12 | }
13 | .uploadNote-img img{
14 | width: 8vh;
15 | border-radius: 50%;
16 | object-fit: contain;
17 | }
18 | .uploadNote-post{
19 | width: 100%;
20 | border: 3px dotted #216bb9;
21 | display: flex;
22 | padding: 10px;
23 | align-items: center;
24 | cursor: pointer;
25 | justify-content: space-between;
26 | }
27 | .uploadNote-post-text{
28 | font-weight: 300;
29 | font-size: 30px;
30 | }
31 |
32 | .uploadNote-form-container{
33 | height: 65vh;
34 | display: flex;
35 | flex-direction: column;
36 | padding: 8px;
37 | border: 2px dotted #2a78cb;
38 | }
39 | .upload-note-top{
40 | display: flex;
41 | justify-content: space-between;
42 | border-bottom: 1px solid brown;
43 | align-items: center;
44 | height: 12vh;
45 | box-shadow: rgba(0, 0, 0, 0.1) 0px 0.0625em 0.0025em, rgba(0, 0, 0, 0.1) 0px 0.025em 0.1em, rgba(255, 255, 255, 0.1) 0px 0px 0px 1px inset;
46 | }
47 | .upload-note-top-left{
48 | display: flex;
49 | align-items: center;
50 | }
51 | #close-icon{
52 | cursor: pointer;
53 | }
54 | .upload-note-title{
55 | font-size: 25px;
56 | }
57 | #upload-note-input{
58 | font-size: 16px;
59 | font-weight: 300;
60 | height: 7vh;
61 | width: 95%;
62 | padding: 10px;
63 | border-top: none;
64 | border-right: none;
65 | border-left: none;
66 | outline: none;
67 | margin-top: 2vh;
68 | }
69 | .uploadNote-form{
70 | display: flex;
71 | flex-direction: column;
72 | }
73 | .uploadNote-form-submit-button{
74 | margin-top: 3vh;
75 | padding: 9px;
76 | font-size: 20px;
77 | width: 12%;
78 | outline: none;
79 | border: none;
80 | color: white;
81 | background-color: #167eec;
82 | cursor: pointer;
83 | }
84 | .custom-file-upload{
85 | padding: 8px;
86 | display: flex;
87 | justify-content: space-between;
88 | align-items: center;
89 | height: 7vh;
90 | margin-top: 3vh;
91 | width: 40%;
92 | background-color: #f5f7f9;
93 | cursor: pointer;
94 | }
95 | .custom-file-upload p{
96 | font-size: 20px;
97 | font-weight: 300;
98 | }
99 | .img-icon{
100 | color: white;
101 | }
102 | #thumbnail-file-upload::-webkit-file-upload-button {
103 | visibility: hidden;
104 | }
105 |
106 | @media only screen and (max-width: 768px) {
107 | .uploadNote-container-top{
108 | height: 7vh;
109 | }
110 | .uploadNote-img img{
111 | width: 7vh;
112 | }
113 | .uploadNote-post{
114 | border: 2px dotted #216bb9;
115 | padding:4px;
116 | }
117 | .uploadNote-post-text{
118 | font-size: 22px;
119 | }
120 |
121 | .uploadNote-form-container{
122 | height: 59vh;
123 | padding: 5px;
124 | }
125 | .upload-note-title{
126 | font-size: 22px;
127 | }
128 | #upload-note-input{
129 | font-size: 14px;
130 | font-weight: 300;
131 | height: 7vh;
132 | width: 95%;
133 | padding: 5px;
134 | }
135 | .uploadNote-form-submit-button{
136 | padding: 6px;
137 | font-size: 16px;
138 | width: 100%;
139 | }
140 | .custom-file-upload{
141 | padding: 4px;
142 | width: 80%;
143 | }
144 | .custom-file-upload p{
145 | font-size: 16px;
146 | }
147 | }
--------------------------------------------------------------------------------
/frontend/src/component/updateUser/UpdateUser.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 | .Update-container {
7 | display: flex;
8 | padding-top: 2vh;
9 | align-items: center;
10 | justify-content: center;
11 | }
12 | .Update-profile-container {
13 | display: flex;
14 | align-items: center;
15 | justify-content: center;
16 | height: 134vh;
17 | width: 90vw;
18 | background-color: rgba(45, 132, 254, 0.863);
19 | padding: 5vh 2vw;
20 | border-radius: 10px;
21 | }
22 |
23 | .Update-profile-container-left {
24 | background-color: rgb(75 162 240);
25 | display: flex;
26 | flex-direction: column;
27 | align-items: center;
28 | height: 100%;
29 | width: 25%;
30 | padding: 2vh 0;
31 | box-shadow: 0 6px 13px rgb(40, 114, 199);
32 | border-radius: 10px;
33 | }
34 | .Update-profile-container-left-top {
35 | display: flex;
36 | flex-direction: column;
37 | align-items: center;
38 | }
39 | .Update-profile-container-left-top-user-desc {
40 | display: flex;
41 | flex-direction: column;
42 | align-items: center;
43 | }
44 | .Update-profile-container-left-top-img {
45 | width: 50px;
46 | height: 50px;
47 | border-radius: 50%;
48 | object-fit: cover;
49 | }
50 |
51 | .Update-profile-container-left-top-name {
52 | margin-bottom: 0;
53 | padding-bottom: 0;
54 | font-size: 20px;
55 | font-weight: 600;
56 | color: white;
57 | }
58 | .Update-profile-container-left-top-username {
59 | font-size: 15px;
60 | font-weight: 300;
61 | color: white;
62 | }
63 | .Update-profile-container-right {
64 | height: 100%;
65 | width: 75%;
66 | border-radius: 10px;
67 | background-color: white;
68 | display: flex;
69 | flex-direction: column;
70 | padding: 2vh 2vh;
71 | box-shadow: 0 6px 13px rgb(155, 169, 184);
72 | }
73 | .Update-profile-container-right-heading {
74 | font-size: 30px;
75 | color: cadetblue;
76 | font-weight: 600;
77 | text-align: center;
78 | }
79 | .Update-profile-container-right-form {
80 | display: flex;
81 | flex-direction: column;
82 | width: 100%;
83 | height: 100vh;
84 | }
85 | .input-box {
86 | height: 11vh;
87 | width: 95%;
88 | margin-bottom: 2vh;
89 | }
90 | .input-block {
91 | height: 6vh;
92 | width: 95%;
93 | border: 1px solid grey;
94 | border-radius: 5px;
95 | padding: 3px 1vw;
96 | }
97 | .input-heading {
98 | font-size: 14px;
99 | font-weight: 500;
100 | margin-bottom: 0;
101 | }
102 |
103 | .Update-profile-container-right-form-submit {
104 | background-color: #3E8DE3;
105 | color: white;
106 | border: 1px solid grey;
107 | border-radius: 10px;
108 | font-size: 20px;
109 | font-weight: 300;
110 | width: 25%;
111 | padding: 2vh;
112 | cursor: pointer;
113 | }
114 | .Update-profile-container-right-form-submit:active {
115 | font-size: 26px;
116 | }
117 | .Update-profile-container-right-form-submit {
118 | background-color: #3E8DE3;
119 | box-shadow: 0 6px 13px grey;
120 | font-size: 22px;
121 | }
122 | @media only screen and (max-width: 768px) {
123 | .Update-profile-container {
124 | width: 97vw;
125 | height: 125vh;
126 | }
127 | .Update-profile-container-left {
128 | display: none;
129 | }
130 | .Update-profile-container-right-form {
131 | width: 100%;
132 | }
133 | .Update-profile-container-right {
134 | padding: 2vh 4vh;
135 | width: 100%;
136 | }
137 | .Update-profile-container-right-heading {
138 | font-size: 18px;
139 | }
140 |
141 | .input-block {
142 | font-size: 16px;
143 | height: 5vh;
144 | }
145 | .Update-profile-container-right-form-submit {
146 | font-size: 15px;
147 | padding: 2vh;
148 | width: 40%;
149 | }
150 | #input-bloack-file {
151 | font-size: 12px;
152 | width: 100%;
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/frontend/src/component/BuildConversation/BuildConversation.jsx:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import styled from "styled-components";
3 | import { useState,useEffect} from "react";
4 | import './BuildConversation.css';
5 | import { useSelector, useDispatch } from "react-redux";
6 | import { mobile } from "../../responsive"
7 | import CircularLoader from '../../component/CircularLoader'
8 | import { publicRequest } from '../../requestMethods'
9 | import {CallMissedSharp, Search,Send} from "@material-ui/icons";
10 | import { makeStyles } from "@material-ui/core/styles";
11 | import { Navigate, useNavigate } from "react-router";
12 | import SearchedUser from "../SearchedUser/SearchedUser";
13 |
14 | const Container = styled.div`
15 | width: 100%;
16 | display: flex;
17 | flex-wrap: wrap;
18 | justify-content: space-between;
19 | background-color:#3E8DE3;
20 | border-radius: 10px;
21 | padding: 10px;
22 | `;
23 | const MessageContainer=styled.div`
24 | height: 13vh;
25 | width: 100%;
26 | display: flex;
27 | border-radius: 10px;
28 | flex-direction: column;
29 | justify-content: center;
30 | ${mobile({alignItems:"center"})}
31 | align-items: flex-start;
32 | `
33 | const MessageTitle=styled.div`
34 | font-size: 30px;
35 | color: white;
36 | font-weight: 700;
37 | `
38 | const Wrapper = styled.div`
39 | display: flex;
40 | justify-content: center;
41 | width: 100%;
42 | `;
43 | const SearchContainer = styled.form`
44 | border-radius: 10px;
45 | display: flex;
46 | align-items: center;
47 | padding: 5px;
48 | width: 100%;
49 | ${mobile({ width: "80%" })}
50 | background-color:white;
51 | `;
52 |
53 | const Input = styled.input`
54 | border: none;
55 | outline: none;
56 | width: 100%;
57 | border-radius: 10px;
58 | height: 40px;
59 | font-size: 15px;
60 | ${mobile({ height: "30px" })}
61 | padding: 5px;
62 | `;
63 | const SearchButton = styled.button`
64 | border: none;
65 | outline: none;
66 | background-color: white;
67 | `;
68 | const UserWrapper=styled.div`
69 | background-color:white;
70 | height: 70vh;
71 | display: flex;
72 | width: 100%;
73 | padding: 10px;
74 | flex-direction: column;
75 | `;
76 |
77 |
78 | const RenderPost = () => {
79 |
80 | const [issearching, setissearching] = useState(false);
81 | const [searchedItem, setsearchedItem] = useState(null);
82 | const [users, setUsers] = useState(null);
83 | const dispatch = useDispatch();
84 |
85 | const searchHandler = async (e) => {
86 | e.preventDefault();
87 | setissearching(true)
88 | const res= await publicRequest.get("users/findusers/"+searchedItem);
89 | setUsers(res.data);
90 | setissearching(false)
91 | };
92 | return (
93 | <>
94 |
95 |
96 | Chat with users
97 |
98 |
99 |
100 | setsearchedItem(e.target.value)}
103 | required
104 | />
105 |
106 |
107 |
108 |
109 |
110 |
111 | {
112 | issearching?:
113 |
114 | {
115 | users?.length===0 ? Not Found :
116 | users?.map((u,i)=>())
117 | }
118 |
119 | }
120 | >
121 | );
122 | };
123 |
124 | export default RenderPost;
125 |
--------------------------------------------------------------------------------
/frontend/src/pages/login/Login.jsx:
--------------------------------------------------------------------------------
1 | import { useState } from "react";
2 | import styled from "styled-components";
3 | import { login } from "../../redux/apiCalls";
4 | import { mobile } from "../../responsive.js";
5 | import { useDispatch, useSelector } from "react-redux";
6 | import {Link} from 'react-router-dom'
7 |
8 | const Container = styled.div`
9 | width: 100vw;
10 | height: 100vh;
11 | /* background: linear-gradient(
12 | rgba(255, 255, 255, 0.5),
13 | rgba(255, 255, 255, 0.5)
14 | ),
15 | url("https://img.freepik.com/free-vector/online-document-concept-illustration_114360-5453.jpg?w=900&t=st=1673501437~exp=1673502037~hmac=f7a813ace48ce8a1ce1be58c1d1507746faa24876235b9c94f44584380ed1cd5")
16 | center; */
17 | background-repeat: no-repeat;
18 | background-size: contain;
19 | display: flex;
20 | flex-direction: column;
21 | align-items: center;
22 | justify-content: center;
23 |
24 | `;
25 |
26 | const Wrapper = styled.div`
27 | width: 25%;
28 | padding: 20px;
29 | background-color: white;
30 | ${mobile({ width: "75%" })}
31 | box-shadow: rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, rgba(10, 37, 64, 0.35) 0px -2px 6px 0px inset;
32 | `;
33 | const TitleNav=styled.h1`
34 | font-size: 45px;
35 | font-weight: 200;
36 | text-align: center;
37 | margin-bottom: 3vh;
38 | `
39 | const Title = styled.h1`
40 | font-size: 24px;
41 | font-weight: 300;
42 | `;
43 |
44 | const Form = styled.form`
45 | display: flex;
46 | flex-direction: column;
47 | `;
48 |
49 | const Input = styled.input`
50 | flex: 1;
51 | min-width: 40%;
52 | margin: 10px 0;
53 | padding: 10px;
54 | ${mobile({border:"1px solid brown"})}
55 | `;
56 |
57 | const Button = styled.button`
58 | width: 40%;
59 | border: none;
60 | padding: 15px 20px;
61 | background-color: #3967bc;
62 | color: white;
63 | cursor: pointer;
64 | margin-bottom: 10px;
65 | &:disabled {
66 | background-color: #27457e;
67 | cursor: not-allowed;
68 | }
69 | `;
70 |
71 | const LinkTag = styled.a`
72 | margin: 5px 0px;
73 | font-size: 12px;
74 | text-decoration: none;
75 | `;
76 |
77 | const Error = styled.span`
78 | color: #3f76e5;
79 | `;
80 |
81 | const Login = () => {
82 | const [email, setEmail] = useState("");
83 | const [password, setPassword] = useState("");
84 | const dispatch = useDispatch();
85 | const { currentUser, isFetching, error } = useSelector((state) => state.user);
86 |
87 |
88 | const handleClick = (e) => {
89 | e.preventDefault();
90 | login(dispatch, { email, password });
91 | };
92 | return (
93 |
94 | NoteSharing
95 |
96 | SIGN IN
97 |
126 |
127 |
128 | );
129 | };
130 |
131 | export default Login;
--------------------------------------------------------------------------------
/frontend/src/component/updatepost/UpdatePost.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useRef } from "react";
2 | import "./UpdatePost.css";
3 | import { useState, useEffect } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import axios from "axios";
6 | import { publicRequest } from "../../requestMethods";
7 | import {useParams } from "react-router-dom";
8 | import { useSelector } from "react-redux";
9 | import Navbar from '../Navbar'
10 | function UpdatePost() {
11 | const { notesid } = useParams();
12 | const { currentUser: user } = useSelector((state) => state.user);
13 | const [notename, setnotename] = useState();
14 | const [desc, setdesc] = useState();
15 | const [noteupdatedphoto, setnoteupdatedphoto] = useState(null);
16 | const [noteupdatedfile, setnoteupdatedfile] = useState("");
17 |
18 | const navigate = useNavigate();
19 |
20 | const UpdateNoteHandler = async (e) => {
21 | e.preventDefault();
22 | alert("Updating started...");
23 | const newNote = {
24 | userId: user._id,
25 | notename: notename,
26 | desc: desc,
27 | notefilename: noteupdatedfile,
28 | };
29 | if (noteupdatedphoto) {
30 | const data = new FormData();
31 | data.append("file", noteupdatedphoto);
32 | data.append("upload_preset", "handnoteimages");
33 | const res = await axios.post(
34 | "https://api.cloudinary.com/v1_1/dw2fok6if/image/upload",
35 | data
36 | );
37 | newNote.thumbnailfilename = await res.data.secure_url;
38 |
39 | }
40 | try {
41 | await publicRequest.put(`notes/${notesid}`,newNote);
42 | alert("successfully uploaded...");
43 | navigate("/");
44 | } catch (err) {}
45 | };
46 | return (
47 | <>
48 |
49 |
50 |
51 |
Update your note
52 |
99 |
100 |
101 | >
102 | );
103 | }
104 |
105 | export default UpdatePost;
106 |
--------------------------------------------------------------------------------
/frontend/src/component/banner/Banner.jsx:
--------------------------------------------------------------------------------
1 | import React, { Component, createContext } from "react";
2 | import "react-responsive-carousel/lib/styles/carousel.min.css";
3 | import { Carousel } from "react-responsive-carousel";
4 | import {Spinner} from 'react-bootstrap';
5 | import "./Banner.css";
6 | import { Link } from "react-router-dom";
7 | import { useState, useEffect } from "react";
8 | import axios from "axios";
9 | import Profile from "../../pages/profile/Profile";
10 | const Banner = () => {
11 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
12 | const [users, setusers] = useState([]);
13 | const [notes, setnotes] = useState([]);
14 | const [len, setlen] = useState(0);
15 | const [isuser,setisuser]=useState(false)
16 | const [isnotes,setisnotes]=useState(false);
17 | const TotalPublishNotes=createContext();
18 | useEffect(() => {
19 | const fetchalluser = async () => {
20 | const res = await axios.get("https://notesharingbackend-ankitkr437.onrender.com/api/users/");
21 | setusers(res.data);
22 | setisuser(true);
23 | };
24 | const fetchallnotes = async () => {
25 | const res = await axios.get("https://notesharingbackend-ankitkr437.onrender.com/api/notes/");
26 | setnotes(res.data);
27 | setisnotes(true);
28 | };
29 | fetchallnotes();
30 | fetchalluser();
31 | }, []);
32 |
33 | const topauthor = [];
34 | const showauthor = [];
35 | users.map((x, i) => {
36 | topauthor[i] = notes.filter(function (obj) {
37 | return obj.userId == x._id;
38 | });
39 | });
40 |
41 | {
42 | topauthor.sort((a, b) => {
43 | return b.length - a.length;
44 | });
45 | }
46 | topauthor.map((x, i) => {
47 | if (x.length > 0) {
48 | showauthor[i] = x;
49 | }
50 | });
51 | {
52 | showauthor.sort((a, b) => {
53 | return b.length - a.length;
54 | });
55 | }
56 |
57 | return (
58 | <>
59 | {
60 | (isnotes && isuser)?
61 |
62 |
73 | {showauthor.map((x, i) => {
74 | if (x.length > 0) {
75 | return (
76 |
77 |
78 |
79 |
80 |
81 |
82 |
obj._id==x[0].userId).profilePicture?users.find((obj)=>obj._id==x[0].userId).profilePicture:pf+"DefaultBoy.jpg"
85 | }
86 | className="banner-image"
87 | />
88 |
89 |
90 |
91 |
95 |
96 | {i + 1}.
97 | {users.find((obj) => obj._id == x[0].userId).username}
98 |
99 |
100 |
101 | Total published notes :{x.length}
102 |
103 |
104 |
105 |
106 |
107 | );
108 | }
109 | })}
110 |
111 | :
112 | }
113 | >
114 | );
115 | };
116 |
117 | export default Banner;
118 |
--------------------------------------------------------------------------------
/frontend/src/pages/home/center/RenderPost.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import HomePost from "./Homepost.js";
3 | import styled from "styled-components";
4 | import axios from "axios";
5 | import { Search,ArrowForward} from "@material-ui/icons";
6 | import { useState, useEffect } from "react";
7 | import { search } from "../../../redux/userRedux";
8 | import { useSelector, useDispatch } from "react-redux";
9 | import { mobile } from "../../../responsive";
10 | import CircularLoader from '../../../component/CircularLoader'
11 | import {publicRequest} from '../../../requestMethods'
12 | const Container = styled.div`
13 | padding: 20px;
14 | ${mobile({ padding: "0px" })}
15 | display: flex;
16 | flex-wrap: wrap;
17 | justify-content: space-between;
18 | `;
19 | const Wrapper = styled.div`
20 | display: flex;
21 | justify-content: center;
22 | margin-top: 1vh;
23 | margin-bottom: 3vh;
24 | ${mobile({ marginTop: "1vh"})}
25 | `;
26 | const SearchContainer = styled.form`
27 | border: 1px solid lightgray;
28 | display: flex;
29 | align-items: center;
30 | padding: 5px;
31 | ${mobile({ width: "80%" })}
32 | `;
33 |
34 | const Input = styled.input`
35 | border: none;
36 | outline: none;
37 | width: 500px;
38 | height: 40px;
39 | font-size: 16px;
40 | ${mobile({ height: "30px" })}
41 | padding: 5px;
42 | `;
43 | const SearchButton = styled.button`
44 | border: none;
45 | outline: none;
46 | background-color: white;
47 | `;
48 | const ShowmoreButton = styled.button`
49 | margin: auto;
50 | border: none;
51 | outline: none;
52 | background-color:#3E8DE3;
53 | display: flex;
54 | font-size: 18px;
55 | align-items: center;
56 | justify-content: center;
57 |
58 | padding: 2vh;
59 | padding-left: 3vh;
60 | padding-right: 3vh;
61 | cursor: pointer;
62 | color: white;
63 | border-radius: 5px;
64 | &:hover {
65 | background-color: #1b65b1;
66 | }
67 | `;
68 |
69 | const RenderPost = () => {
70 | const { currentUser:user, searchedValue } = useSelector((state) => state.user);
71 | const [notes, setnotes] = useState([]);
72 | const [issearching, setissearching] = useState(false);
73 | const [postcount,setpostcount]=useState(5);
74 | const [searchedItem, setsearchedItem] = useState(searchedValue);
75 | const dispatch = useDispatch();
76 | useEffect(() => {
77 | const fetchallnotes = async () => {
78 | setissearching(true)
79 | if(!searchedValue){
80 | const res = await publicRequest.get(`notes/?count=${postcount}`);
81 | setnotes(
82 | res.data.sort((n1, n2) => {
83 | return new Date(n2.createdAt) - new Date(n1.createdAt);
84 | })
85 | );
86 | }
87 | else{
88 | const res= await publicRequest.get("notes/findnotes/"+searchedItem);
89 | setnotes(res.data);
90 | }
91 | setissearching(false)
92 | };
93 | fetchallnotes();
94 | }, [user._id,searchedValue,postcount]);
95 |
96 |
97 | const searchHandler = async (e) => {
98 | e.preventDefault();
99 | dispatch(search(searchedItem));
100 | };
101 | useEffect(() => {
102 | dispatch(search(null));
103 | }, []);
104 | console.log(postcount)
105 | if (issearching) return ;
106 | return (
107 | <>
108 |
109 |
110 |
111 | setsearchedItem(e.target.value)}
114 | />
115 |
116 |
117 |
118 |
119 |
120 | {
121 | notes?.length===0 ? Not Found :
122 | notes.map((p,i)=>)
123 | }
124 | {setpostcount(postcount+5)}}>Show More
125 | >
126 | );
127 | };
128 |
129 | export default RenderPost;
130 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # NoteShare - Share Your Notes!
3 |
4 | NoteShare is a web application that allows users to share their notes with others and interact with fellow users through a built-in chat feature. With NoteShare, you can easily create, manage, and share your notes while **connecting with like-minded individuals**.
5 |
6 | 
7 |
8 |
9 | ## Features
10 |
11 | - **User Profiles:** Every user gets their own profile where they can view and manage their notes, as well as see their activity and engagement on the platform.
12 |
13 | 
14 |
15 |
16 | - **Note Sharing:** Share your notes with the community which will help others to get more on that topic.
17 |
18 |
19 | - **React on Notes:** React like if you like the notes also one can add the comment over the post of note
20 |
21 |
22 | - **Note Management:** Organize your notes using some description and add note titles for easy retrieval.
23 |
24 |
25 | - **Chat with Other Users:** Engage in **real-time conversations** with other users through the built-in chat feature. Discuss topics, exchange knowledge, and build connections.
26 |
27 | 
28 |
29 |
30 | - **Privacy and Security:** NoteShare prioritizes the **security and privacy** of its users. All user data is encrypted and kept confidential.
31 |
32 | ## How to Use NoteShare
33 |
34 | 1. **Sign Up / Log In:** If you're a new user, create an account by providing your email and password. If you're an existing user, simply log in to your account.
35 |
36 | 2. **Create a Note:** To share a note, int home page click on "Upload Note." Write your note, add relevant description, titles and your url of notes where you have uploaded the note
37 |
38 | 
39 |
40 |
41 | 4. **Explore Shared Notes:** find notes shared by other users. You can filter notes by tags, categories, or popularity on the searchBox by typing specific text.
42 |
43 | 5. **Chat with Users:** To start a conversation, click on the "Chat" button. search for particular user and click on that user now You can have one-on-one chats.
44 |
45 | 
46 |
47 |
48 | 7. **Manage Your Notes:** In your profile, you can view and manage all your notes. Edit, delete, or update.
49 |
50 |
51 | ## Technologies Used
52 |
53 | NoteShare is built using a combination of cutting-edge technologies:
54 |
55 | - Frontend: HTML, CSS, JavaScript, **React.js**
56 | - Backend: **Node.js**, **Express.js**
57 | - Database: **MongoDB**
58 | - Real-time Communication: **WebSockets**
59 |
60 | ## Installation
61 |
62 | To run NoteSharing locally, follow these steps:
63 |
64 | 1. Clone this repository to your local machine.
65 | ```bash
66 | git clone https://github.com/your-username/notesharing.git
67 | ```
68 |
69 | 2. Install the dependencies for both the frontend and backend.
70 | ```bash
71 | # Navigate to the frontend directory
72 | cd NoteSharing/frontend
73 | npm install
74 |
75 | # Navigate to the backend directory
76 | cd ../backend
77 | npm install
78 |
79 | # Navigate to the socket directory
80 | cd ../socket
81 | npm install
82 | ```
83 |
84 | 3. Set up your MongoDB database and update the connection string in `backend/.env`.
85 | 4. Replace BASE_URL to LocalBASE_URL in frontend/src/requestMethods.js.
86 | 5. For using the messenger, Replace EndPoint to your locally running socket url in frontend/src/pages/messenger/messenger.jsx.
87 | 6. Start the development servers for both the frontend and backend.
88 | ```bash
89 | # In the backend directory
90 | npm start
91 | # In the socket directory
92 | npm start
93 | # In the frontend directory
94 | npm start
95 | ```
96 | 7. Visit `http://localhost:3000` in your web browser to access NoteShare.
97 |
98 | ## Contribution
99 |
100 | We welcome contributions to make NoteShare better! If you have any bug fixes, feature implementations, or suggestions, feel free to open an issue or submit a pull request.
101 |
102 | ## License
103 |
104 | NoteShare is licensed under the [**MIT License**](https://github.com/ankitkr437/NoteSharing/blob/main/LICENSE). Feel free to use, modify, and distribute the code for personal and commercial projects.
105 |
106 | ## Contact
107 |
108 | If you have any questions, feedback, or inquiries, please contact us at **ankitloharshi@gmail.com** or visit our [**website**](https://notesharing.onrender.com/).
109 |
110 | Happy Note Sharing! 📝
111 |
--------------------------------------------------------------------------------
/backend/routes/users.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | const router = express.Router();
3 | import bcrypt from 'bcrypt'
4 | import User from '../model/Userschema.js'
5 | import Note from '../model/Userschema.js'
6 |
7 |
8 | //update user
9 | router.put("/:id", async (req, res) => {
10 |
11 | if (req.body.password) {
12 | try {
13 | const salt = await bcrypt.genSalt(10);
14 | req.body.password = await bcrypt.hash(req.body.password, salt);
15 | } catch (err) {
16 | return res.status(500).json(err);
17 | }
18 | }
19 | try {
20 | const user = await User.findByIdAndUpdate(req.params.id, {
21 | $set: req.body,
22 | });
23 | res.status(200).json("Account has been updated");
24 | } catch (err) {
25 | return res.status(500).json(err);
26 | }
27 |
28 | });
29 |
30 |
31 | //delete
32 | router.delete("/:id", async (req, res) => {
33 | if (req.body.userId === req.params.id || req.body.isAdmin) {
34 | try {
35 | await User.findByIdAndDelete(req.params.id);
36 | res.status(200).json("Account has been deleted");
37 | } catch (err) {
38 | return res.status(500).json(err);
39 | }
40 | } else {
41 | return res.status(403).json("You can delete only your account!");
42 | }
43 | });
44 |
45 | //get a user
46 | router.get("/:id", async (req, res) => {
47 | try {
48 | const user = await User.findById(req.params.id);
49 | //we do not need unnecessaary information about user like password updated at
50 | //user._doc is basically all object
51 | const { password, updatedAt, ...other } = user._doc;
52 | res.status(200).json(other);
53 | } catch (err) {
54 | res.status(500).json(err);
55 | }
56 | });
57 |
58 | //follow a user
59 | router.put("/:id/follow", async (req, res) => {
60 | if (req.body.userId !== req.params.id) {
61 | try {
62 | const user = await User.findById(req.params.id);
63 | const currentUser = await User.findById(req.body.userId);
64 | if (!user.followers.includes(req.body.userId)) {
65 | await user.updateOne({ $push: { followers: req.body.userId } });
66 | await currentUser.updateOne({ $push: { followings: req.params.id } });
67 | res.status(200).json("user has been followed");
68 | } else {
69 | res.status(403).json("you allready follow this user");
70 | }
71 | } catch (err) {
72 | res.status(500).json(err);
73 | }
74 | } else {
75 | res.status(403).json("you cant follow yourself");
76 | }
77 | });
78 |
79 |
80 | //unfollow a user
81 |
82 | router.put("/:id/unfollow", async (req, res) => {
83 | if (req.body.userId !== req.params.id) {
84 | try {
85 | const user = await User.findById(req.params.id);
86 | const currentUser = await User.findById(req.body.userId);
87 | if (user.followers.includes(req.body.userId)) {
88 | await user.updateOne({ $pull: { followers: req.body.userId } });
89 | await currentUser.updateOne({ $pull: { followings: req.params.id } });
90 | res.status(200).json("user has been unfollowed");
91 | } else {
92 | res.status(403).json("you dont follow this user");
93 | }
94 | } catch (err) {
95 | res.status(500).json(err);
96 | }
97 | } else {
98 | res.status(403).json("you cant unfollow yourself");
99 | }
100 | });
101 |
102 |
103 |
104 | //get all user
105 | router.get("/", async (req, res) => {
106 | try {
107 | const data =await User.find();
108 | res.status(200).json(data);
109 | } catch (err) {
110 | res.status(404).json(err);
111 | }
112 | });
113 |
114 | //find a user by some keyword
115 | router.get("/findusers/:keyword", async (req, res) => {
116 |
117 | try {
118 | const data =await User.find({$or:[{'username' : new RegExp(req.params.keyword, 'i')},{'firstname' : new RegExp(req.params.keyword, 'i')}]});
119 | res.status(200).json(data);
120 | } catch (err) {
121 | res.status(404).json(err);
122 | }
123 | });
124 |
125 | //GET all featured authors
126 | router.get("/getauthors", async (req, res) => {
127 | try {
128 | const data =await User.find();
129 | res.status(200).json(data);
130 | } catch (err) {
131 | res.status(404).json(err);
132 | }
133 | });
134 |
135 |
136 | //GET USER STATS
137 |
138 | router.get("/stats/authors", async (req, res) => {
139 | try {
140 | const data = await User.aggregate(
141 | [
142 | { "$project": {
143 | "username":1,
144 | "profilePicture":1,
145 | "followers_length":{ "$size": "$followers" },
146 | "institution":1,
147 | "notes_length": { "$size": "$notes" }
148 | }},
149 | { "$sort": { "notes_length": -1 } },
150 | { "$limit": 10 }
151 | ])
152 | res.status(200).json(data)
153 | } catch (err) {
154 | res.status(500).json(err);
155 | }
156 | });
157 |
158 |
159 |
160 | export default router;
161 |
162 |
--------------------------------------------------------------------------------
/frontend/src/component/topbar/Topbar.jsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useEffect, useRef,Component } from "react";
2 | import "./Topbar.css";
3 | import { Link} from "react-router-dom";
4 | import {
5 | LibraryBooksTwoTone,
6 | CloseRounded,
7 | } from "@material-ui/icons";
8 | import { useState } from "react";
9 |
10 | import {publicRequest} from'../../requestMethods'
11 | import {useSelector,useDispatch} from 'react-redux'
12 | import {logout,search} from "../../redux/userRedux";
13 | const Topbar = () => {
14 | const {curreUser:user,searchedValue} =useSelector((state)=>state.user)
15 | const [searchedItem,setsearch] =useState("");
16 | const menu=useRef();
17 | const [placeholder, setplaceholder] = useState("..");
18 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
19 | const dispatch=useDispatch();
20 | const MenuClickHandler=()=>{
21 | if(menu.current.style.display=="flex" )
22 | {
23 | menu.current.style.display="none";
24 | }
25 | else if(menu.current.style.display="none" && user._id)
26 | menu.current.style.display="flex";
27 | }
28 |
29 | const logouthandler=()=>{
30 | dispatch(logout());
31 | }
32 |
33 | const searchsubmit=(e)=>{
34 | e.preventDefault();
35 | dispatch(search(searchedItem));
36 | }
37 | useEffect(()=>{
38 | dispatch(search(null));
39 | },[])
40 |
41 | return (
42 | <>
43 |
44 |
45 |
46 | {" "}
47 |
48 |
49 |
HandNotes
50 |
51 |
52 |
53 |
54 |
55 |
74 |
75 | { user &&
76 |
77 |
78 |
79 | }
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
{user?user.username:"Not Available"}
95 |
96 |
97 |
98 |
99 |
View Profile
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
Setting
112 |
113 |
114 |
115 |
Logout
116 |
119 |
120 |
121 |
122 |
123 |
124 | >
125 | );
126 | };
127 |
128 | export default Topbar;
129 |
--------------------------------------------------------------------------------
/frontend/src/component/uploadNote/UploadNote.js:
--------------------------------------------------------------------------------
1 | import React, {useRef } from "react";
2 | import "./UploadNote.css";
3 | import { useState} from "react";
4 | import axios from "axios";
5 | import {useSelector} from 'react-redux'
6 | import {
7 | CloudUpload,Close,PictureAsPdf,AddCircle,Image,
8 | } from "@material-ui/icons";
9 | import { publicRequest } from "../../requestMethods";
10 | import { makeStyles } from "@material-ui/core/styles";
11 | import { mobile } from "../../responsive";
12 | const useStyles = makeStyles(theme => ({
13 | uploadIcon: {
14 | color:"#167eec",
15 | fontSize:"3rem",
16 | },
17 | UploadPdfIcon:{
18 | color:"#167eec",
19 | fontSize:"3rem",
20 | },
21 | closeIcon:{
22 | fontSize:"3rem"
23 | },
24 | uploadAdd:{
25 | color:"#167eec",
26 | fontSize:"3rem",
27 | },
28 | upload:{
29 | color:"#167eec",
30 | fontSize:"2rem",
31 | }
32 | }));
33 | const UploadNote = () => {
34 | const {currentUser:user} = useSelector((state)=>state.user)
35 | const pf="https://notesharingbackend-ankitkr437.onrender.com/images/";
36 |
37 | const ShowForm = useRef();
38 | const notename = useRef();
39 | const descritpion = useRef();
40 | const [isupload,setsetisupload]=useState(false)
41 | const [fileurl,setfileurl]=useState("")
42 | const [fileimg,setfileimg]=useState(null)
43 | const ShowFormHandler = () => {
44 | if ((ShowForm.current.style.display = "flex"))
45 | ShowForm.current.style.display = "none";
46 | };
47 | const uploadNoteFormSubmitHandler = async (e) => {
48 |
49 | alert("Uploading started, it will take few minutes...")
50 | e.preventDefault();
51 | const newNote = {
52 | userId: user._id,
53 | desc: descritpion.current.value,
54 | notename:notename.current.value,
55 | notefilename :fileurl,
56 | };
57 | if (fileimg) {
58 | const data = new FormData();
59 | data.append("file", fileimg);
60 | data.append("upload_preset", 'handnoteimages');
61 | const res=await axios.post("https://api.cloudinary.com/v1_1/dw2fok6if/image/upload",data)
62 | newNote.thumbnailfilename = await res.data.secure_url;
63 |
64 | }
65 | try {
66 | await publicRequest.post("/notes", newNote);
67 | window.location.reload();
68 | alert("successfully uploaded")
69 | } catch (err) {}
70 | };
71 | const classes = useStyles();
72 | return (
73 | <>
74 | {
75 | !isupload &&
76 | {setsetisupload((curr) => !curr);}}>
77 |
78 |
79 | Upload a Note
80 |
81 |
82 |
83 | }
84 | { isupload &&
85 |
86 |
87 |
88 | Upload a Note
89 |
90 |
{setsetisupload((curr) => !curr);}} className={classes.closeIcon} id="close-icon"/>
91 |
92 |
133 |
134 | }
135 | >
136 | );
137 | };
138 |
139 | export default UploadNote;
140 |
--------------------------------------------------------------------------------
/backend/routes/notes.js:
--------------------------------------------------------------------------------
1 | import express from 'express';
2 | const router =express.Router();
3 | import User from '../model/Userschema.js';
4 | import Note from '../model/Noteschema.js';
5 |
6 | //create a post for selling a note
7 |
8 | router.post("/", async (req, res) => {
9 | const newNote = new Note(req.body);
10 | try {
11 | const savedNote = await newNote.save();
12 | const user = await User.findById(savedNote.userId);
13 | await user.updateOne({ $push: { notes: savedNote._id } });
14 | res.status(200).json(savedNote);
15 | } catch (err) {
16 | res.status(500).json(err);
17 | }
18 | });
19 |
20 |
21 | //update a note
22 | // here params id is of one post id created by itself mongo db
23 |
24 | router.put("/:id", async (req, res) => {
25 | try {
26 | const note = await Note.findById(req.params.id);
27 | if (note.userId === req.body.userId) {
28 | await note.updateOne({ $set: req.body });
29 | res.status(200).json("the post has been updated");
30 | } else {
31 | res.status(403).json("you can update only your post");
32 | }
33 | } catch (err) {
34 | res.status(500).json(err);
35 | }
36 | });
37 | //delete a post
38 |
39 | router.delete("/:id", async (req, res) => {
40 | try {
41 | const note = await Note.findById(req.params.id);
42 | const user = await User.findById(note.userId);
43 | await user.updateOne({ $pull: { notes: note._id } });
44 | await note.deleteOne();
45 | res.status(200).json("the post has been deleted");
46 |
47 | } catch (err) {
48 | res.status(500).json(err);
49 | }
50 | });
51 |
52 |
53 | //like / dislike a post
54 |
55 | router.put("/:id/like", async (req, res) => {
56 | try {
57 | const note = await Note.findById(req.params.id);
58 | if (!note.likes.includes(req.body.userId)) {
59 | await note.updateOne({ $push: { likes: req.body.userId } });
60 | res.status(200).json("The note has been liked");
61 | } else {
62 | await note.updateOne({ $pull: { likes: req.body.userId } });
63 | res.status(200).json("The note has been disliked");
64 | }
65 | } catch (err) {
66 | res.status(500).json(err);
67 | }
68 | });
69 |
70 |
71 | //buy a notes
72 |
73 | router.put("/:id/buy", async (req, res) => {
74 | try {
75 | const note = await Note.findById(req.params.id);
76 | if (!note.buy.includes(req.body.userId)) {
77 | await note.updateOne({ $push: { buy: req.body.userId} });
78 | res.status(200).json("The note has been selled");
79 | } else {
80 | res.status(200).json("You already has been buy this note ");
81 | }
82 | } catch (err) {
83 | res.status(500).json(err);
84 | }
85 | });
86 |
87 |
88 | //get a post
89 | //here id is notes id
90 | router.get("/:id", async (req, res) => {
91 | try {
92 | const note = await Note.findById(req.params.id).limit(10);
93 | res.status(200).json(note);
94 | } catch (err) {
95 | res.status(500).json(err);
96 | }
97 | });
98 |
99 | //get timeline posts
100 | // here params userId is a current user of which we have to find all post and also to find its followings post this is what we create a timeline
101 | // Promise.all(): This is a static method that takes an array of promises as input and returns a new promise. The new promise resolves when all the input promises in the array are resolved, and it rejects if any of the input promises reject.
102 | router.get("/timeline/:userId", async (req, res) => {
103 | try {
104 | const currentUser = await User.findById(req.params.userId);
105 | const userNotes = await Note.find({ userId: currentUser._id });
106 | const followingsNotes = await Promise.all(
107 | currentUser.followings.map((followingsId) => {
108 | return Note.find({ userId: followingsId });
109 | })
110 | );
111 | res.status(200).json(userNotes.concat(...followingsNotes));
112 | } catch (err) {
113 | res.status(500).json(err);
114 | }
115 | });
116 | //get user's all posts
117 |
118 | router.get("/profile/:userId", async (req, res) => {
119 | try {
120 | const posts = await Note.find({ userId: req.params.userId });
121 | res.status(200).json(posts);
122 | } catch (err) {
123 | res.status(500).json(err);
124 | }
125 | });
126 |
127 | //GET all notes
128 | router.get("/", async (req, res) => {
129 | try {
130 | console.log(req.query)
131 | const count=req.query.count?req.query.count:10;
132 | const notes= await Note.find().limit(count);
133 | notes.reverse();
134 | res.status(200).json(notes);
135 | } catch (err) {
136 | res.status(500).json(err);
137 | }
138 | });
139 |
140 |
141 |
142 |
143 | //find a note by some name
144 | router.get("/findnotes/:keyword", async (req, res) => {
145 |
146 | try {
147 | const data =await Note.find({$or:[{'desc' : new RegExp(req.params.keyword, 'i')},{'notename' : new RegExp(req.params.keyword, 'i')}]});
148 | res.status(200).json(data);
149 | } catch (err) {
150 | res.status(404).json(err);
151 | }
152 | });
153 |
154 | export default router;
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/frontend/src/pages/register/Register.jsx:
--------------------------------------------------------------------------------
1 | import styled from "styled-components";
2 | import { mobile } from "../../responsive";
3 | import { useDispatch, useSelector } from "react-redux";
4 | import { useState,useEffect } from "react";
5 | import { Link } from "react-router-dom";
6 | import { register } from "../../redux/apiCalls";
7 | const Container = styled.div`
8 | width: 100vw;
9 | height: 100vh;
10 | /* background: linear-gradient(
11 | rgba(255, 255, 255, 0.5),
12 | rgba(255, 255, 255, 0.5)
13 | ),
14 | url("https://img.freepik.com/free-vector/online-document-concept-illustration_114360-5453.jpg?w=900&t=st=1673501437~exp=1673502037~hmac=f7a813ace48ce8a1ce1be58c1d1507746faa24876235b9c94f44584380ed1cd5")
15 | center; */
16 | background-repeat: no-repeat;
17 | background-size: contain;
18 | display: flex;
19 | flex-direction: column;
20 | align-items: center;
21 | justify-content: center;
22 | ${mobile({paddingTop:"12vh" })}
23 | `;
24 | const TitleNav=styled.h1`
25 | font-size: 45px;
26 | font-weight: 200;
27 | text-align: center;
28 | margin-bottom: 3vh;
29 | ${mobile({textAlign:"center",fontSize:"35px",marginBottom:"1vh"})}
30 | `
31 | const Wrapper = styled.div`
32 |
33 | width: 40%;
34 | padding: 20px;
35 | background-color: white;
36 | ${mobile({ width: "75%" , marginTop:"2vh"})}
37 | box-shadow: rgba(50, 50, 93, 0.25) 0px 50px 100px -20px, rgba(0, 0, 0, 0.3) 0px 30px 60px -30px, rgba(10, 37, 64, 0.35) 0px -2px 6px 0px inset;
38 | `;
39 |
40 | const Title = styled.h1`
41 | font-size: 24px;
42 | font-weight: 300;
43 | ${mobile({fontSize:"20px"})}
44 | `;
45 |
46 | const Form = styled.form`
47 | display: flex;
48 | flex-wrap: wrap;
49 | ${mobile({flexDirection:"column",flexWrap:"nowrap"})}
50 | `;
51 |
52 | const Input = styled.input`
53 | flex: 1;
54 | min-width: 40%;
55 | margin: 20px 10px 0px 0px;
56 | padding: 10px;
57 | ${mobile({border:"1px solid brown"})}
58 | `;
59 |
60 | const Agreement = styled.span`
61 | font-size: 10px;
62 | margin-bottom: 20px;
63 | margin-top: 5px;
64 | `;
65 |
66 | const Button = styled.button`
67 | width: 40%;
68 | display: block;
69 | border: none;
70 | padding: 15px 20px;
71 | background-color: #3967bc;
72 | color: white;
73 | cursor: pointer;
74 | &:disabled {
75 | background-color: #223f74;
76 | cursor: not-allowed;
77 | }
78 | `;
79 | const LinkTag = styled.a`
80 | margin-top: 20px;
81 | font-size: 12px;
82 | display: block;
83 | text-decoration: none;
84 | `;
85 | const Error = styled.span`
86 | color: red;
87 | `;
88 |
89 | const Register = () => {
90 | const [firstname, setFirstname] = useState("");
91 | const [lastname, setLastname] = useState("");
92 | const [username, setUsername] = useState("");
93 | const [email, setEmail] = useState("");
94 | const [password, setPassword] = useState("");
95 | const [confirmpassword, setConfirmPassword] = useState("");
96 |
97 | const dispatch = useDispatch();
98 | const { isFetching, error} = useSelector((state) => state.user);
99 |
100 | const handleClick = (e) => {
101 | e.preventDefault();
102 | password=== confirmpassword ?
103 | register(dispatch,{
104 | firstname,lastname,username,email, password,
105 | }) : alert("password is not same")
106 |
107 | }
108 |
109 | return (
110 |
111 | NoteSharing
112 |
113 | CREATE AN ACCOUNT
114 |
158 |
159 |
160 | );
161 | };
162 |
163 | export default Register;
--------------------------------------------------------------------------------
/frontend/src/pages/profile/Profile.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | padding: 0%;
4 | margin: 0%;
5 | }
6 | .profile-container {
7 | width: 100%;
8 | padding-left: 10vw;
9 | padding-right: 10vw;
10 | padding-top: 4vh;
11 | }
12 | .profile-top {
13 | display: flex;
14 | }
15 |
16 | .profile-top-img-container {
17 | display: flex;
18 | flex: 2;
19 | flex-direction: column;
20 | align-items: center;
21 | }
22 | .profile-top-img-container img {
23 | width: 20vh;
24 | height: 20vh;
25 | padding: 0.2vh;
26 | object-fit: cover;
27 | border-radius: 50%;
28 | border: 1px solid gray;
29 | }
30 | .username {
31 | font-size: 17px;
32 | font-weight: 600;
33 | line-height: 20px;
34 | }
35 | .profile-desc {
36 | display: flex;
37 | flex: 7;
38 | flex-direction: column;
39 | justify-content: center;
40 | width: 100%;
41 | line-height: 3px;
42 | }
43 | .fullname {
44 | font-size: 20px;
45 | font-weight: 800;
46 | line-height: 17px;
47 | }
48 | .institution-container {
49 | display: flex;
50 | margin-top: 1vh;
51 | }
52 | .institution-container img {
53 | height: 15px;
54 | width: 15px;
55 | }
56 | .institution {
57 | font-size: 14px;
58 | line-height: 17px;
59 | }
60 | .desc {
61 | font-size: 16px;
62 | font-weight: 500;
63 | line-height: 17px;
64 | }
65 | .user-resident {
66 | display: flex;
67 | line-height: 17px;
68 | margin-top: 1vh;
69 | }
70 | .user-resident img {
71 | height: 12px;
72 | width: 12px;
73 | }
74 | .residing-first {
75 | font-size: 12px;
76 | font-weight: 300;
77 | }
78 | .residing-second {
79 | font-size: 12px;
80 | font-weight: 300;
81 | }
82 |
83 | .followers-followings {
84 | display: flex;
85 | margin-top: 1vh;
86 | }
87 | .followers-followings p {
88 | line-height: 17px;
89 | font-size: 15px;
90 | margin-left: 1px;
91 | margin-right: 1px;
92 | font-weight: 400;
93 | color: rgb(54, 51, 51);
94 | }
95 | .follow-chat {
96 | display: flex;
97 | width: 35%;
98 | }
99 |
100 | .start-conversation-1 {
101 | display: flex;
102 | margin-left: 1vh;
103 | flex: 3;
104 | justify-content: center;
105 | /* padding-top: 1vh; */
106 | height: 7vh;
107 | border: none;
108 | border-radius: 5vh;
109 | box-shadow: 0px 0px 10px 7px rgb(233, 238, 233);
110 | background-color: rgb(115, 155, 247);
111 | }
112 | .button-text {
113 | display: flex;
114 | align-items: center;
115 | justify-content: center;
116 | }
117 | .start-conversation-1 p {
118 | font-size: 16px;
119 | color: white;
120 | margin: 0;
121 | margin-right: 3px;
122 | }
123 | .start-conversation-1 img {
124 | width: 20px;
125 | height: 20px;
126 | }
127 | .start-conversation-1:hover {
128 | cursor: pointer;
129 | background-color: rgb(82, 124, 224);
130 | }
131 |
132 | .follow {
133 | box-shadow: 0px 1px 3px rgb(108, 172, 241);
134 | color: white;
135 | box-shadow: 0px 0px 7px 7px rgb(233, 238, 233);
136 | background-color: rgb(115, 155, 247);
137 | border: none;
138 | display: flex;
139 | align-items: center;
140 | font-size: 16px;
141 | cursor: pointer;
142 | font-weight: 500;
143 | margin-right: 5vh;
144 | margin-top: 2vh;
145 | padding: 10px 15px;
146 | }
147 | .follow:hover {
148 | background-color: rgb(82, 124, 224);
149 | }
150 | .follow-icon {
151 | color: rgb(255, 255, 255);
152 | }
153 |
154 | .contributions {
155 | display: flex;
156 | justify-content: space-between;
157 | margin-top: 4vh;
158 | width: 100%;
159 | }
160 | .gain-container {
161 | display: flex;
162 | flex-direction: column;
163 | align-items: center;
164 | }
165 | .total-gain {
166 | height: 15vh;
167 | width: 10vw;
168 | display: flex;
169 | border: 1px solid brown;
170 | padding: 1vh 1vh;
171 | background-color: #3E8DE3;
172 | align-items: center;
173 | justify-content: space-evenly;
174 | margin-bottom: 2vh;
175 | }
176 | .total-gain img {
177 | width: 45px;
178 | height: 45px;
179 | }
180 | .gain-value {
181 | color: white;
182 | font-size: 34px;
183 | }
184 | .gain-desc {
185 | font-size: 15px;
186 | }
187 | .user-post-profile {
188 | display: flex;
189 | flex-direction: column;
190 | width: 100%;
191 | align-items: center;
192 | }
193 | .user-timeline {
194 | display: flex;
195 | height: 100%;
196 | width: 100%;
197 | margin-top: 10vh;
198 | }
199 | .contributions-phone {
200 | display: none;
201 | }
202 |
203 | @media only screen and (max-width: 768px) {
204 | .profile-container {
205 | width: 100%;
206 | padding-left: 3vw;
207 | padding-right: 3vw;
208 | }
209 | .profile-top-img-container img {
210 | width: 10vh;
211 | height: 10vh;
212 | }
213 | .user-timeline {
214 | display: block;
215 | margin-top: 6vh;
216 | }
217 | .profile-desc {
218 | padding-left: 1vh;
219 | }
220 | .follow-chat {
221 | width: 75%;
222 | }
223 | .follow {
224 | width: 24vw;
225 | height: 5vh;
226 | margin-right: 1vh;
227 | }
228 | .start-conversation-1 {
229 | height: 5vh;
230 | }
231 | .user-post-profile {
232 | width: 100%;
233 | margin-right: 0vw;
234 | }
235 | .user-timeline {
236 | padding-left: 0vw;
237 | }
238 | .total-gain {
239 | height: 12vh;
240 | width: 22vw;
241 | }
242 | .total-gain img {
243 | width:30px;
244 | height: 30px;
245 | }
246 | .gain-value {
247 | color: white;
248 | font-size: 26px;
249 | }
250 | .gain-desc {
251 | font-size: 12px;
252 | }
253 | }
254 |
--------------------------------------------------------------------------------
/frontend/src/pages/messenger/messenger.jsx:
--------------------------------------------------------------------------------
1 | import "./messenger.css";
2 | import Navbar from "../../component/Navbar";
3 | import Conversation from "../../component/conversations/Conversation";
4 | import Message from "../../component/message/Message"
5 | import ChatOnline from "../../component/chatOnline/chatOnline";
6 | import {useEffect, useRef, useState } from "react";
7 | import { useSelector } from "react-redux";
8 | import {publicRequest} from '../../requestMethods'
9 | import { io } from "socket.io-client";
10 |
11 | export default function Messenger() {
12 | const [conversations, setConversations] = useState([]);
13 | const [currentChat, setCurrentChat] = useState(null);
14 | const [messages, setMessages] = useState([]);
15 | const [newMessage, setNewMessage] = useState("");
16 | const [arrivalMessage, setArrivalMessage] = useState(null);
17 | const [onlineUsers, setOnlineUsers] = useState([]);
18 | const socket = useRef();
19 | const { currentUser:user } = useSelector((state)=>state.user)
20 | const scrollRef = useRef();
21 |
22 | useEffect(() => {
23 | // https://notesharing-socket.onrender.com/
24 | const EndPoint="https://notesharing-socket.onrender.com/";
25 | socket.current = io(EndPoint);
26 | socket.current.on("getMessage", (data) => {
27 | setArrivalMessage({
28 | sender: data.senderId,
29 | text: data.text,
30 | createdAt: Date.now(),
31 | });
32 | });
33 | }, []);
34 |
35 | useEffect(() => {
36 | arrivalMessage &&
37 | currentChat?.members.includes(arrivalMessage.sender) &&
38 | setMessages((prev) => [...prev, arrivalMessage]);
39 | }, [arrivalMessage, currentChat]);
40 |
41 | useEffect(() => {
42 | socket.current.emit("addUser", user._id);
43 | socket.current.on("getUsers", (users) => {
44 | setOnlineUsers(
45 | user.followings.filter((f) => users.some((u) => u.userId === f))
46 | );
47 | });
48 | }, [user]);
49 |
50 | useEffect(() => {
51 | const getConversations = async () => {
52 | try {
53 | const res = await publicRequest.get("/conversations/" + user._id);
54 | setConversations(res.data);
55 | } catch (err) {
56 | console.log(err);
57 | }
58 | };
59 | getConversations();
60 | }, [user._id]);
61 | console.log(conversations)
62 | useEffect(() => {
63 | const getMessages = async () => {
64 | try {
65 | const res = await publicRequest.get("/messages/" + currentChat?._id);
66 | setMessages(res.data);
67 | } catch (err) {
68 | console.log(err);
69 | }
70 | };
71 | getMessages();
72 | }, [currentChat]);
73 |
74 | const handleSubmit = async (e) => {
75 | e.preventDefault();
76 | const message = {
77 | sender: user._id,
78 | text: newMessage,
79 | conversationId: currentChat._id,
80 | };
81 |
82 | const receiverId = currentChat.members.find(
83 | (member) => member !== user._id
84 | );
85 |
86 | socket.current.emit("sendMessage", {
87 | senderId: user._id,
88 | receiverId,
89 | text: newMessage,
90 | });
91 |
92 | try {
93 | const res = await publicRequest.post("/messages", message);
94 | setMessages([...messages, res.data]);
95 | setNewMessage("");
96 | } catch (err) {
97 | console.log(err);
98 | }
99 | };
100 |
101 | useEffect(() => {
102 | scrollRef.current?.scrollIntoView({ behavior: "smooth" });
103 | }, [messages]);
104 |
105 | return (
106 | <>
107 |
108 |
109 |
110 |
111 |
112 | {conversations.map((c) => (
113 |
setCurrentChat(c)}>
114 |
115 |
116 | ))}
117 |
118 |
119 |
120 |
121 | {currentChat ? (
122 | <>
123 |
124 | {messages.map((m) => (
125 |
126 |
127 |
128 | ))}
129 |
130 |
131 | setNewMessage(e.target.value)}
135 | value={newMessage}
136 | >
137 |
138 | Send
139 |
140 |
141 | >
142 | ) : (
143 |
144 | Open a conversation to start a chat.
145 |
146 | )}
147 |
148 |
149 |
150 |
Online Users
151 |
152 |
157 |
158 |
159 |
160 | >
161 | );
162 | }
--------------------------------------------------------------------------------
/frontend/src/component/post/Post.css:
--------------------------------------------------------------------------------
1 | *{
2 | box-sizing: border-box;
3 | padding: 0;
4 | margin: 0%;
5 | }
6 | .post-container{
7 | display: flex;
8 | height: 82vh;
9 | width: 60%;
10 | flex-direction: column;
11 | margin-bottom: 8vh;
12 | box-shadow: rgba(50, 50, 93, 0.25) 0px 6px 12px -2px, rgba(0, 0, 0, 0.3) 0px 3px 7px -3px;
13 | position: relative;
14 | }
15 | .post-topbar{
16 | height: 13vh;
17 | padding: 1vh 1vh;
18 | display: flex;
19 | background-color: #3E8DE3;
20 | }
21 | .post-topbar-img{
22 | width: 60px;
23 | border-radius: 50%;
24 | object-fit: cover;
25 | height: 60px;
26 | }
27 | .post-topbar-desc{
28 | display: flex;
29 | flex-direction: column;
30 | }
31 | .post-topbar-name{
32 | font-size: 18px;
33 | font-weight: 700;
34 | color: rgb(8, 43, 43);
35 | }
36 | .post-topbar-desc{
37 | margin-left: 1vh;
38 | display: flex;
39 | flex-direction: column;
40 | justify-content: space-evenly;
41 | }
42 | .post-topbar-follow-ago-container{
43 | display: flex;
44 | justify-content: space-between;
45 | }
46 | .post-topbar-follow-ago-container p{
47 | font-size: 12px;
48 | font-weight: 300;
49 | line-height: 2px;
50 | color:black;
51 | }
52 | .post-topbar-edit-delete-container{
53 | display: flex;
54 | justify-content: space-around;
55 | width: 10vw;
56 | right: 0;
57 | height: 9vh;
58 | align-items: center;
59 | position:absolute;
60 | margin-top: 2vh;
61 | }
62 |
63 | .post-topbar-delete-icon:hover{
64 | cursor: pointer;
65 | }
66 | .delete-icon{
67 | cursor: pointer;
68 | }
69 | .main-post{
70 | display: flex;
71 | }
72 | .main-post-img-container{
73 | position: relative;
74 | display: flex;
75 | justify-content: center;
76 | align-items: center;
77 | width: 40%;
78 | }
79 | .main-post-img-container img{
80 | width: 100%;
81 | height:57vh;
82 | }
83 | .main-post-about{
84 | width: 60%;
85 | display: flex;
86 | flex-direction: column;
87 | padding: 1vh 1vw;
88 | }
89 | .main-post-notename{
90 | font-size:23px;
91 | font-weight: 700;
92 | }
93 | .main-post-description{
94 | font-size: 19px;
95 | font-weight: 600;
96 | color: rgb(71, 66, 66);
97 | margin-bottom: -2px;
98 | }
99 | .main-post-desc{
100 | font-size: 14px;
101 | font-weight: 400;
102 | color: rgb(95, 88, 88);
103 | }
104 | .View-pdf-1{
105 | position: absolute;
106 | display: flex;
107 | flex-direction: row;
108 | justify-content: center;
109 | align-items: center;
110 | background-color: #3E8DE3;
111 | width: 110px;
112 | height: 8vh;
113 | box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 3px, rgba(0, 0, 0, 0.24) 0px 1px 2px;
114 | }
115 | .View-pdf-1:hover{
116 | background-color: #3E8DE3;
117 | cursor: pointer;
118 | }
119 | .View-pdf-1 p{
120 | font-size: 16px;
121 | font-weight: 600;
122 | color: white;
123 | }
124 | .View-pdf-1 img{
125 | height: 20px;
126 | border-radius: 0;
127 | width: 20px;
128 | margin-bottom: 1vh;
129 | margin-left: 1vh;
130 | }
131 | .post-reaction-container{
132 | display: flex;
133 | justify-content: space-between;
134 | align-items: center;
135 | margin-top: 2vh;
136 | padding-left: 1vw;
137 | padding-right: 1vw;
138 | }
139 | .post-reaction{
140 | display: flex;
141 | background-color: rgb(200, 225, 253);
142 | border-radius: 35px;
143 | width: 10vw;
144 | height: 7vh;
145 | font-size: 20px;
146 | align-items: center;
147 | justify-content: center;
148 | }
149 | .post-reaction p{
150 | margin-left: 5px;
151 | }
152 | .post-container{
153 | width: 100%;
154 | }
155 |
156 | @media only screen and (max-width: 700px) {
157 | .post-container{
158 | height: 56vh;
159 | padding-bottom:2vh;
160 | margin-bottom: 3vh;
161 | width: 100%;
162 | }
163 | .post-topbar-img{
164 | width: 42px;
165 | height: 42px;
166 | }
167 | .post-topbar-name{
168 | font-size: 15px;
169 | font-weight: 700;
170 | color: rgb(8, 43, 43);
171 | }
172 | .post-topbar-desc{
173 | margin-left: 1vh;
174 | display: flex;
175 | flex-direction: column;
176 | justify-content: space-evenly;
177 | }
178 | .post-topbar{
179 | height: 9vh;
180 | }
181 | .post-topbar-follow-ago-container p{
182 | font-size: 10px;
183 | line-height: 0px;
184 | }
185 |
186 | .post-topbar-delete-icon{
187 | height: 24px;
188 | width: 24px;
189 | }
190 | .post-topbar-edit-icon img{
191 | height: 24px;
192 | width: 24px;
193 | }
194 | .post-reaction img {
195 | height: 21px;
196 | width: 21px;
197 | /* margin-top: 1.5vh; */
198 | }
199 | .post-reaction p{
200 | font-size: 15px;
201 | }
202 | .post-reaction{
203 | width: 22vw;
204 | height: 5vh;
205 | }
206 | .post-reaction-seen-img{
207 | height: 28px;
208 | width: 28px;
209 | }
210 | .post-topbar-edit-delete-container {
211 | width: 25vw;
212 | margin-top: 0vh;
213 | }
214 | .main-post-img-container img{
215 | height:39vh;
216 | width: 100%;
217 | }
218 | .main-post{
219 | height: 40vh;
220 | }
221 | .main-post-notename{
222 | font-size:20px;
223 | }
224 | .main-post-description{
225 | font-size: 15px;
226 | }
227 | .main-post-desc{
228 | font-size: 11px;
229 | }
230 | .View-pdf-1{
231 | width: 105px;
232 | height: 7vh;
233 | }
234 | .View-pdf-1 img{
235 | height: 18px;
236 | width: 18px;
237 | }
238 | .View-pdf-1 p{
239 | font-size: 14px;
240 | }
241 | }
242 |
243 |
--------------------------------------------------------------------------------
/frontend/src/component/Navbar.jsx:
--------------------------------------------------------------------------------
1 | import { Badge } from "@material-ui/core";
2 | import { Search, Chat, Menu,AccountCircle,ExitToApp } from "@material-ui/icons";
3 | import React, { useEffect, useState } from "react";
4 | import { useNavigate } from 'react-router-dom';
5 | import styled from "styled-components";
6 | import { mobile } from "../responsive";
7 | import { useSelector,useDispatch} from "react-redux";
8 | import { Link } from "react-router-dom";
9 | import {logout,search} from "../redux/userRedux";
10 | import { useRef } from "react";
11 | import TopNavbar from './TopNavbar/TopNavbar'
12 | const Container = styled.div`
13 | height: 60px;
14 | ${mobile({ height: "50px" })}
15 | `;
16 |
17 | const Wrapper = styled.div`
18 | padding: 10px 20px;
19 | display: flex;
20 | align-items: center;
21 | justify-content: space-between;
22 | ${mobile({ padding: "10px 10px" })}
23 | `;
24 |
25 | const Left = styled.div`
26 | flex: 1;
27 | display: flex;
28 | align-items: center;
29 | ${mobile({ flex:5 })}
30 | `;
31 |
32 | const Language = styled.span`
33 | font-size: 14px;
34 | cursor: pointer;
35 | ${mobile({ display: "none" })}
36 | `;
37 |
38 | const SearchContainer = styled.form`
39 | border: 1px solid lightgray;
40 | display: flex;
41 | align-items: center;
42 | margin-left: 25px;
43 | ${mobile({ marginLeft:"0px" })}
44 | padding: 5px;
45 | `;
46 |
47 | const Input = styled.input`
48 | border: none;
49 | outline: none;
50 | ${mobile({ width: "120px" })}
51 | `;
52 |
53 | const Center = styled.div`
54 | flex: 1;
55 | text-align: center;
56 |
57 | `;
58 |
59 | const Logo = styled.h1`
60 | font-weight: bold;
61 | ${mobile({ fontSize: "24px",display:"none" })}
62 | `;
63 | const Right = styled.div`
64 | flex: 1;
65 | display: flex;
66 | align-items: center;
67 | justify-content: space-around;
68 | ${mobile({ flex: 10, justifyContent: "space-around" })}
69 | `;
70 |
71 | const MenuItem = styled.div`
72 | display: flex;
73 | align-items: center;
74 | cursor: pointer;
75 | margin-left: 25px;
76 | ${mobile({marginLeft: "15px", marginRight:"5px",flexDirection:"column" })}
77 | `;
78 | const Item=styled.p`
79 | font-size: 20px;
80 | margin-left: "2px";
81 | color: #115195;
82 | ${mobile({ fontSize: "13px"})}
83 | `
84 | const CartItem = styled.div`
85 | font-size: 14px;
86 | cursor: pointer;
87 | margin-left: 25px;
88 | ${mobile({ fontSize: "12px", marginLeft: "15px" ,marginRight:"5px" })}
89 | `;
90 | const Button = styled.button`
91 | border: none;
92 | background: none;
93 | outline: none;
94 | cursor: pointer;
95 | margin-left: 2px;
96 | font-size: 20px;
97 | color: #185393;
98 | ${mobile({fontSize:"13px"})}
99 | `;
100 | const SearchButton = styled.button`
101 | border: none;
102 | outline: none;
103 | background-color: white;
104 | `;
105 | const TopNavWrapper=styled.div`
106 | display: none;
107 | ${mobile({ display:"block" })}
108 | `
109 |
110 |
111 | const Navbar = () => {
112 | // const quantity = useSelector(state=>state.cart.quantity)
113 | const currentUser= useSelector(state=>state.user.currentUser)
114 | const [searchedValue,setsearchedValue]=useState(null)
115 | const item=useRef();
116 | let navigate = useNavigate();
117 | const dispatch = useDispatch();
118 | const logoutHandler=()=>{
119 | dispatch(logout());
120 | navigate("/login");
121 | }
122 | const searchHandler=(e)=>{
123 | e.preventDefault();
124 | dispatch(search(searchedValue));
125 | }
126 | useEffect(()=>{
127 | dispatch(search(null));
128 | },[])
129 | const HandleNav =()=>{
130 | console.log(item.current.display)
131 | if(item.current.display==="flex"){
132 | item.current.display="none";
133 | }
134 | else{
135 | item.current.display="flex";
136 | }
137 | }
138 | return (
139 | <>
140 |
141 |
142 |
143 |
144 |
145 |
146 | EN
147 |
148 | setsearchedValue(e.target.value)}/>
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | NoteSharing
157 |
158 |
159 |
160 |
161 | {
162 | currentUser?
163 | <>
164 |
165 |
166 |
167 |
168 | -
169 | {currentUser.username}
170 |
171 |
172 |
173 |
174 |
175 |
176 | Logout
177 |
178 | >
179 | :
180 | <>
181 |
182 |
183 | SignIn
184 |
185 |
186 |
187 |
188 | Register
189 |
190 |
191 | >
192 | }
193 |
194 |
195 |
196 |
197 | -
198 | Chat
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 | >
207 | );
208 | };
209 |
210 | export default Navbar;
--------------------------------------------------------------------------------
/frontend/src/component/updateUser/UpdateUser.js:
--------------------------------------------------------------------------------
1 | import React, { useContext, useRef } from "react";
2 | import "./UpdateUser.css";
3 | import { useState, useEffect } from "react";
4 | import { useNavigate } from "react-router-dom";
5 | import axios from "axios";
6 | import { publicRequest } from "../../requestMethods";
7 | import { useSelector } from "react-redux";
8 | import Navbar from '../Navbar';
9 | const UpdateUser = () => {
10 | const pf = "https://notesharingbackend-ankitkr437.onrender.com/images/";
11 | const { currentUser: user } = useSelector((state) => state.user);
12 | const [firstname, setfirstname] = useState();
13 | const [lastname, setlastname] = useState();
14 | const [institution, setinstitution] = useState();
15 | const [interested, setinterested] = useState();
16 | const [photo, setphoto] = useState(null);
17 | const [password, setpassword] = useState();
18 |
19 | const navigate = useNavigate();
20 |
21 | const UpdateFormHandler = async (e) => {
22 | e.preventDefault();
23 |
24 | const newUser = {
25 | userId: user._id,
26 | firstname: firstname,
27 | lastname: lastname,
28 | interested: interested,
29 | institution: institution,
30 | password: password,
31 | };
32 | if (photo) {
33 | const data = new FormData();
34 | data.append("file", photo);
35 | data.append("upload_preset", "handnoteimages");
36 | const res = await axios.post(
37 | "https://api.cloudinary.com/v1_1/dw2fok6if/image/upload",
38 | data
39 | );
40 | newUser.profilePicture = await res.data.secure_url;
41 | }
42 | try {
43 | await publicRequest.put(`users/${user._id}`, newUser);
44 | alert("successfully uploaded...");
45 | navigate("/");
46 | } catch (err) {
47 | console.log(err);
48 | }
49 | };
50 |
51 | return (
52 | <>
53 |
54 |
55 |
56 |
57 |
58 |
66 |
67 |
68 |
69 | {user.firstname} {user.lastname}
70 |
71 |
72 | {user.username}
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | Your Personal Profile Info
81 |
82 |
162 |
163 |
164 |
165 | >
166 | );
167 | };
168 |
169 | export default UpdateUser;
170 |
--------------------------------------------------------------------------------
/frontend/src/component/post/Post.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import { Link } from "react-router-dom";
3 | import {
4 | ThumbUp,
5 | ThumbUpAltOutlined,
6 | Visibility,
7 | Comment,
8 | Edit,
9 | Delete,
10 | } from "@material-ui/icons";
11 | import { useNavigate } from "react-router-dom";
12 | import { useState, useEffect } from "react";
13 | import { format } from "timeago.js";
14 | import "./Post.css";
15 | import { useSelector } from "react-redux";
16 | import { publicRequest } from "../../requestMethods";
17 | const Post = ({ note, postUser }) => {
18 | const { currentUser } = useSelector((state) => state.user);
19 | const user = currentUser;
20 | const pf = "https://notesharingbackend-ankitkr437.onrender.com/images/";
21 | const [like, setlike] = useState(note.likes.length);
22 | const [islike, setislike] = useState(false);
23 | const [isseen, setisseen] = useState(false);
24 | const [seen, setseen] = useState(note.buy.length);
25 | const [allcomment, setallcomment] = useState(0);
26 |
27 | const navigate = useNavigate();
28 | useEffect(() => {
29 | setislike(note.likes.includes(user._id));
30 | }, [user._id, note.likes]);
31 |
32 | useEffect(() => {
33 | setisseen(note.buy.includes(user._id));
34 | }, [user._id, note.seen]);
35 | useEffect(() => {
36 | const fetchComment = async (req, res) => {
37 | try {
38 | const res = await publicRequest.get("comments/" + note._id);
39 | setallcomment(res.data);
40 | } catch (err) {
41 | console.log(err);
42 | }
43 | };
44 | fetchComment();
45 | }, []);
46 |
47 | const likehandler = () => {
48 | try {
49 | publicRequest.put("notes/" + note._id + "/like", { userId: user._id });
50 | } catch (err) {}
51 | setlike(islike ? like - 1 : like + 1);
52 | setislike(!islike);
53 | };
54 | const seenhandler = async () => {
55 | try {
56 | await publicRequest.put("notes/" + note._id + "/buy", {
57 | userId: user._id,
58 | });
59 | } catch (err) {}
60 | setseen(isseen ? seen - 1 : seen + 1);
61 | setisseen(!isseen);
62 | window.open(note.notefilename, "_blank").focus();
63 | };
64 | const DeleteNotes = async () => {
65 | let response = prompt(
66 | `Do you really want to delete this note if yes then type "YES" or type "NO" `
67 | );
68 | try {
69 | response === "YES" &&
70 | (await publicRequest.delete(`notes/${note._id}`, { userId: user._id }));
71 | response === "YES" && alert("notes deleted successfully");
72 | response === "YES" && window.location.reload();
73 | } catch (err) {
74 | alert("sorry you can not delete this note");
75 | console.log("unsuccess");
76 | }
77 | };
78 |
79 | return (
80 | <>
81 |
82 |
83 |
87 |
95 |
96 |
97 |
101 |
102 | {postUser && postUser.username}
103 |
104 |
105 |
106 |
{postUser && postUser.followers.length} Followers
107 |
{format(note.createdAt)}
108 |
109 |
110 |
111 | {user && note && note.userId === user._id && (
112 |
113 |
118 |
119 |
120 |
121 |
122 | )}
123 |
124 |
125 |
126 |
127 |
135 |
136 |
View-pdf
137 |
138 |
139 |
140 |
141 |
{note.notename}
142 |
Description:
143 |
{note.desc}
144 |
145 |
146 |
147 |
148 |
149 | {islike ? (
150 |
151 | ) : (
152 |
153 | )}
154 |
{like}
155 |
156 |
161 |
162 |
163 |
{allcomment.length}
164 |
165 |
166 |
167 |
168 |
{note.buy.length}
169 |
170 |
171 |
172 | >
173 | );
174 | };
175 |
176 | export default Post;
177 |
--------------------------------------------------------------------------------
/frontend/src/pages/profile/Profile.js:
--------------------------------------------------------------------------------
1 | import React, { useContext } from "react";
2 | import "./Profile.css";
3 | import Post from '../../component/post/Post'
4 | import { Link, useParams } from "react-router-dom";
5 | import { useState, useEffect } from "react";
6 | import Navbar from "../../component/Navbar";
7 | import {
8 | Add, Remove
9 | } from "@material-ui/icons";
10 | import { publicRequest } from "../../requestMethods";
11 | import { useDispatch, useSelector } from "react-redux";
12 | import { follow, unFollow } from "../../redux/userRedux";
13 | import CircularLoader from '../../component/CircularLoader'
14 | const Profile = () => {
15 |
16 | const { userId } = useParams();
17 | const pf = "https://notesharingbackend-ankitkr437.onrender.com/images/";
18 | const [user, setuser] = useState({})
19 | const [post, setpost] = useState([])
20 | const { currentUser: currentuser } = useSelector((state) => state.user)
21 | const [isfollow, setisfollow] = useState(
22 | currentuser?.followings.includes(userId)
23 | )
24 | const [followerslength, setfollowerslength] = useState(
25 | user?.followers?.length
26 | );
27 | const dispatch = useDispatch();
28 |
29 | useEffect(() => {
30 | const fetchuser = async () => {
31 | const res = await publicRequest.get(`users/${userId}`);
32 | setuser(res.data);
33 | }
34 | const fetchpost = async () => {
35 | const res = await publicRequest.get(`notes/profile/${userId}`);
36 | setpost(res.data);
37 | }
38 | fetchuser();
39 | fetchpost();
40 | }, [userId, isfollow])
41 | const FollowHandle = async () => {
42 | try {
43 | if (isfollow) {
44 | await publicRequest.put(`/users/${user._id}/unfollow`, {
45 | userId: currentuser._id,
46 | });
47 | dispatch(unFollow(user?._id));
48 | setfollowerslength(followerslength - 1)
49 | } else {
50 | await publicRequest.put(`/users/${user._id}/follow`, {
51 | userId: currentuser._id,
52 | });
53 | dispatch(follow(user?._id));
54 | setfollowerslength(followerslength + 1)
55 | }
56 | setisfollow(!isfollow)
57 | } catch (err) {
58 | }
59 | };
60 | const totallikes = post?.reduce((a, v) => a = a + v?.likes.length, 0)
61 | const totalviews = post?.reduce((a, v) => a = a + v?.buy.length, 0)
62 |
63 | return (
64 | <>
65 |
66 | {
67 | user && user.username ? (
68 |
69 |
70 |
71 |
72 |
73 | {user && user.username}
74 |
75 |
76 |
77 |
78 | {
79 | (user.firstname) &&
80 |
81 | {user?.firstname + " " + user?.lastname}
82 |
83 | }
84 |
85 | {(user.desc) &&
86 |
{
87 | user?.desc
88 | }
89 | }
90 |
91 | {(currentuser._id === userId || user.institution) &&
92 |
93 | {user.institution &&
94 |
95 | }
96 |
97 | {(user.institution) &&
98 | user && user.institution
99 | }
100 |
}
101 |
102 |
103 |
{user.followers.length || 0}
104 |
Followers
105 |
.
106 |
{user.followings.length}
107 |
Followings
108 |
109 |
110 | {user.username !== currentuser.username && (
111 |
112 | {isfollow ? "Unfollow" : "Follow"}
113 | {isfollow ? : }
114 |
115 | )}
116 |
117 |
118 |
119 | < div className="gain-container">
120 |
121 |
122 |
{post && post.length}
123 |
124 |
Published Notes
125 |
126 |
127 |
128 |
129 |
130 |
131 |
{post && totallikes}
132 |
133 |
Total likes
134 |
135 |
136 |
137 |
138 |
139 |
{post && totalviews}
140 |
141 |
Total views
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 | {
150 | post && post.map((note) => (
151 |
152 | ))
153 | }
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | )
164 | :
165 |
166 |
167 |
168 | }
169 |
170 | >
171 | );
172 | };
173 |
174 | export default Profile;
175 |
--------------------------------------------------------------------------------
/frontend/src/component/topbar/Topbar.css:
--------------------------------------------------------------------------------
1 |
2 | * {
3 | box-sizing: border-box;
4 | margin: 0;
5 | padding: 0;
6 | }
7 | .topbar-right-Img-left{
8 | display: none;
9 | }
10 | .topbar-right-Img-left-link{
11 | display: none;
12 | }
13 | .topbar {
14 | display: flex;
15 | align-items: center;
16 | justify-content: center;
17 | width: 100%;
18 | height: 9vh;
19 | position: fixed;
20 | background-image: linear-gradient(to right, rgb(190, 192, 196), rgb(77, 77, 83));
21 | z-index: 6;
22 | box-shadow: 0px 1px 3px rgb(25, 37, 25);
23 | }
24 | .topbar-left {
25 | flex: 5;
26 | display: flex;
27 | align-items: center;
28 | justify-content: center;
29 | }
30 | .topbar-title {
31 | font-family: "Shizuru", cursive;
32 | font-size: 28px;
33 | font-weight: 500;
34 | cursor: pointer;
35 | color: black;
36 | }
37 |
38 | .topbar-left-icon {
39 | margin-right: 5px;
40 | cursor: pointer;
41 | margin-bottom: 1vh;
42 | color: black;
43 | }
44 | .topbar-center {
45 | flex:16;
46 | display: flex;
47 | align-items: center;
48 | justify-content: center;
49 | position: relative;
50 | height: 5vh;
51 | }
52 | form{
53 | display: flex;
54 | }
55 | .search-form{
56 | height: 7vh;
57 | width: 100%;
58 | }
59 | .topbar-center-input {
60 | font-size: 18px;
61 | width: 100%;
62 | background-image: linear-gradient(to right, rgb(134, 153, 216), rgb(77, 86, 207));
63 | border-radius: 10px;
64 | animation-name: inputshow;
65 | animation-duration: 0.7s;
66 | animation-timing-function:linear;
67 | animation-direction: alternate;
68 | padding: 3px 2vw;
69 | padding-right: 5vw;
70 | color: rgb(11, 12, 12);
71 | border: 1px solid grey;
72 | }
73 | .topbar-center-input:hover{
74 | box-shadow: 0px 0px 10px 7px rgb(108, 120, 188);
75 | }
76 |
77 | ::-webkit-input-placeholder { /* WebKit, Blink, Edge */
78 | color: rgb(11, 12, 12);
79 | }
80 | :-moz-placeholder { /* Mozilla Firefox 4 to 18 */
81 | color: rgb(11, 12, 12);
82 | opacity: 1;
83 | }
84 | ::-moz-placeholder { /* Mozilla Firefox 19+ */
85 | color: rgb(11, 12, 12);
86 | opacity: 1;
87 | }
88 | :-ms-input-placeholder { /* Internet Explorer 10-11 */
89 | color: rgb(11, 12, 12);
90 | }
91 | ::-ms-input-placeholder { /* Microsoft Edge */
92 | color: rgb(11, 12, 12);
93 | }
94 |
95 | ::placeholder { /* Most modern browsers support this now. */
96 | color: rgb(11, 12, 12);
97 | }
98 |
99 | .search-form label .topbar-center-icon {
100 |
101 | position: absolute;
102 | border-radius: 7px;
103 | width: 5vh;
104 | height: 5vh;
105 | position: absolute;
106 | right: 1vh;
107 | top: 1px;
108 | background-image: none;
109 | background-color: none;
110 | }
111 | .search-form label .topbar-center-icon:hover{
112 | cursor: pointer;
113 | }
114 | @keyframes inputshow{
115 | 0%{
116 | width:0;
117 | }
118 | 100%{
119 | width: 100%;
120 | }
121 | }
122 | .topbar-center-input :focus {
123 | outline: none;
124 | border: none;
125 | }
126 |
127 |
128 | .topbar-right {
129 | flex: 3;
130 | display: flex;
131 | justify-content:center;
132 | align-items:center;
133 | position: relative;
134 | }
135 |
136 | .messenger-icon:hover{
137 | box-shadow: 0px 0px 10px 7px rgb(26, 48, 171);
138 | border-radius: 50%;
139 | }
140 | .topbar-right-Img:hover{
141 | box-shadow: 0px 0px 10px 7px rgb(26, 48, 171);
142 | border-radius: 50%;
143 | }
144 |
145 | .topbar-right-Img {
146 | width: 38px;
147 | height: 38px;
148 | border-radius: 50%;
149 | object-fit: cover;
150 | display: none;
151 | cursor: pointer;
152 | }
153 |
154 |
155 |
156 |
157 |
158 | .menu{
159 | display: none;
160 | flex-direction: column;
161 | width: 40vw;
162 | z-index: 10;
163 | position: fixed;
164 | background-color: rgb(116, 154, 242);
165 | padding: 30px 15px;
166 | animation-name: menushow;
167 | animation-duration: 0.4s;
168 | animation-timing-function:linear;
169 | animation-direction: alternate;
170 | }
171 |
172 | @keyframes menushow{
173 | 0%{
174 | width:0;
175 | }
176 | 100%{
177 | width: 40vw;
178 | }
179 | }
180 | .profile{
181 | display: flex;
182 | height: 10vh;
183 | }
184 |
185 |
186 | .menu-img{
187 | flex: 2;
188 | width: 60px;
189 | height: 60px;
190 | justify-content: center;
191 | text-align: center;
192 | }
193 | .menu-desc{
194 | flex: 4;
195 | justify-content: center;
196 | align-items: center;
197 | }
198 | .menu-cut{
199 | flex: 1;
200 | justify-content: center;
201 | align-items: center;
202 | }
203 |
204 | .menu-username{
205 | line-height: 19px;
206 | font-size: 24px;
207 | font-weight: 400;
208 | }
209 | .topbar-menu-Img{
210 | width: 60px;
211 | height: 60px;
212 | border-radius: 50%;
213 | object-fit: cover;
214 | }
215 | .menu-cut-icon{
216 | font-size: 80px;
217 | }
218 | .menu-cut-icon:hover{
219 | cursor: pointer;
220 | }
221 | .menu-view-profile{
222 | color: darkblue;
223 | font-weight: 600;
224 | font-size: 19px;
225 | }
226 |
227 |
228 | .profile{
229 | display: flex;
230 | height: 10vh;
231 | justify-content: center;
232 |
233 | }
234 |
235 | .profile-update-menu{
236 | display: flex;
237 | align-items: center;
238 | margin-left: 2vh;
239 | }
240 | .profile-update-menu:hover{
241 | text-decoration: underline;
242 | }
243 | .profile-update-link-tag{
244 | font-size: 20px;
245 | font-weight: 600;
246 | color: darkblue;
247 | }
248 | .topbar-setting{
249 | height: 23px;
250 | width: 23px;
251 | margin-bottom: 2vh;
252 | margin-left: 1vw;
253 | color: darkblue;
254 | }
255 |
256 | #topbar-logout:hover{
257 | text-decoration: underline;
258 | cursor: pointer;
259 | }
260 |
261 |
262 |
263 | @media only screen and (max-width: 768px) {
264 | .topbar-right-Img-left-link{
265 | display: flex;
266 | }
267 | .topbar-right-Img-left{
268 | display: flex;
269 | width: 5vh;
270 | height: 5vh;
271 | border-radius: 30px;
272 | object-fit: cover;
273 |
274 | }
275 | .topbar-title {
276 | font-family: "Shizuru", cursive;
277 | font-size: 19px;
278 | display: none;
279 | font-weight: 800;
280 | margin-left: 2vw;
281 | }
282 | .topbar-left-icon{
283 | display: none;
284 | }
285 | .profile-update-menu-icon{
286 | margin-left: 1vh;
287 | }
288 | .topbar-left {
289 | flex: 1.5;
290 | display: flex;
291 | align-items: center;
292 | justify-content: center;
293 | margin-right: 2%;
294 | }
295 | .topbar-left-icon {
296 | display: none;
297 | }
298 |
299 | .search-form label .topbar-center-icon {
300 | border-radius: 7px;
301 | width: 6vw;
302 | position: absolute;
303 | height: 6vw;
304 | top: 2vw;
305 |
306 | right: 2vw;
307 | }
308 | .topbar-center {
309 | flex: 7;
310 | align-items: center;
311 | justify-content: center;
312 | }
313 |
314 | .search-form{
315 | height: 6vh;
316 | width: 100%;
317 | }
318 | .topbar-right {
319 | flex: 2;
320 | }
321 | .profile-update-link-tag{
322 | font-size: 16px;
323 | margin-right: 10px;
324 | margin-left: 5vw;
325 | }
326 | .topbar-setting{
327 | margin-bottom: 1vh;
328 | }
329 | .topbar-right-img-link{
330 | display: none;
331 | }
332 | .topbar-right-Img {
333 | width: 6vh;
334 | height: 6vh;
335 | border-radius: 50%;
336 | object-fit: cover;
337 | cursor: pointer;
338 | display: flex;
339 | display: none;
340 | }
341 | .topbar-center-input {
342 | font-size: 14px;
343 | padding-right: 9vw;
344 | padding-left: 3vw;
345 | }
346 |
347 |
348 |
349 | .menu{
350 | display: none;
351 | flex-direction: column;
352 | width: 80vw;
353 | z-index: 10;
354 | height: 50vh;
355 | position: fixed;
356 | background-color: rgb(116, 154, 242);
357 | padding: 30px 15px;
358 | animation-name: menushowsmall;
359 | animation-duration: 0.4s;
360 | animation-timing-function:linear;
361 | animation-direction: alternate;
362 | }
363 | @keyframes menushowsmall{
364 | 0%{
365 | width:0;
366 | }
367 | 100%{
368 | width: 80vw;
369 | }
370 | }
371 |
372 | .profile{
373 | display: flex;
374 | height: 10vh;
375 | justify-content: center;
376 |
377 |
378 | }
379 | .menu-img{
380 | flex: 2;
381 | width: 45px;
382 | height: 45px;
383 | }
384 | .menu-desc{
385 | flex: 4;
386 | }
387 | .menu-cut{
388 | flex: 1;
389 | justify-content: center;
390 | align-items: center;
391 | }
392 | .menu-username{
393 | font-size: 16px;
394 | }
395 | .topbar-menu-Img{
396 | width: 7vh;
397 | height: 7vh;
398 | border-radius: 50%;
399 | object-fit: cover;
400 | }
401 | .menu-cut-icon{
402 | font-size: 25px;
403 | }
404 | .menu-view-profile{
405 | color: darkblue;
406 | font-weight: 600;
407 | font-size: 16px;
408 | }
409 |
410 | .menu-view-profile:hover{
411 | text-decoration: underline;
412 | }
413 | .profile-update-menu{
414 | display: flex;
415 | align-items: center;
416 | margin-left: 0;
417 | }
418 | .profile-update-menu:hover{
419 | text-decoration: underline;
420 | }
421 | .profile-update-link-tag{
422 | font-size: 19px;
423 | font-weight: 600;
424 | color: darkblue;
425 | }
426 | .profile-update-menu-icon{
427 | margin-bottom: 2vh;
428 | margin-left: 2vw;
429 | color: rgb(5, 3, 24);
430 | }
431 |
432 | #topbar-logout:hover{
433 | text-decoration: underline;
434 | cursor: pointer;
435 | }
436 | .topbar-setting{
437 | height: 20px;
438 | width: 20px;
439 | margin-left: 0;
440 | }
441 | }
442 |
443 |
444 | @media only screen and (max-height: 450px) {
445 | .search-form label .topbar-center-icon {
446 | display: none;
447 | }
448 | }
449 |
--------------------------------------------------------------------------------