├── README.md ├── one-social-media ├── .gitignore ├── README.md ├── jsconfig.json ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public │ ├── default_profile.jpeg │ ├── facebook.svg │ ├── hareesh.png │ ├── home-hero.avif │ ├── next copy.svg │ ├── next.svg │ ├── osm-white.png │ ├── osm.png │ ├── portFolio.png │ ├── vercel copy.svg │ └── vercel.svg ├── src │ └── app │ │ ├── Context │ │ └── UserContest.jsx │ │ ├── QueryProvider.js │ │ ├── components │ │ ├── Avatar.jsx │ │ ├── Footer.jsx │ │ ├── LogoPart.jsx │ │ ├── NavBar.jsx │ │ ├── Post │ │ │ ├── Like.jsx │ │ │ ├── MakePost.jsx │ │ │ ├── Post.jsx │ │ │ ├── PostInput.jsx │ │ │ └── comment │ │ │ │ ├── Comment.jsx │ │ │ │ └── CommentInput.jsx │ │ ├── ReplyAvatar.jsx │ │ ├── homecomponents │ │ │ ├── FriendRequest.jsx │ │ │ ├── Friends.jsx │ │ │ ├── Profile │ │ │ │ ├── ProfileCard.jsx │ │ │ │ ├── ProfilePhotoUpdate.jsx │ │ │ │ ├── ViewProfile.jsx │ │ │ │ └── profileUpdate.jsx │ │ │ ├── Suggestion.jsx │ │ │ └── message.jsx │ │ ├── imagecrop │ │ │ ├── canvasPreview.jsx │ │ │ ├── crop.jsx │ │ │ └── useDebounceEffect.jsx │ │ ├── login │ │ │ └── Main.jsx │ │ └── useDebounceEffect.jsx │ │ ├── data │ │ └── Data.js │ │ ├── favicon.ico │ │ ├── globals.css │ │ ├── home │ │ └── page.jsx │ │ ├── layout.js │ │ ├── page.js │ │ └── utils │ │ └── api.js └── tailwind.config.js └── server ├── .gitignore ├── config.js ├── controllers ├── authController.js ├── comments.js ├── passwordReset.js ├── post.js ├── userControl.js └── users.js ├── middleware.js ├── models ├── commentModel.js ├── emailVerificatin.js ├── passwordResetSchema.js ├── postModel.js ├── requestSchema.js └── userModels.js ├── package.json ├── pnpm-lock.yaml ├── routes └── auth.js ├── server.js ├── utils ├── index.js ├── passwordChange.js ├── passwordResetRequest.js └── sendVerification.js ├── vercel.json └── views ├── index.html └── passwordReset.html /README.md: -------------------------------------------------------------------------------- 1 | ## ABOUT 2 | Connecting people, new post at a time. Welcome to one social media platform for sharing moments, connecting with friends, and discovering what matters to you. Join the community today and make every day memorable. 3 | 4 | ## SAMPLE PHOTOS 5 | ![](https://res.cloudinary.com/sociladb/image/upload/v1710575479/samples/important/osm/eaftrj7pl3sercyialkg.png) 6 | 7 | ![](https://res.cloudinary.com/sociladb/image/upload/v1710575479/samples/important/osm/llw2auxybqs3k6o8yfte.png) 8 | 9 | ![](https://res.cloudinary.com/sociladb/image/upload/v1710575480/samples/important/osm/a53qomi3dlahz7bvd7yx.png) 10 | 11 | ![](https://res.cloudinary.com/sociladb/image/upload/v1710575480/samples/important/osm/shlpqc3a4mvchpmzpajo.png) 12 | -------------------------------------------------------------------------------- /one-social-media/.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 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | .env 31 | 32 | # vercel 33 | .vercel 34 | 35 | # typescript 36 | *.tsbuildinfo 37 | next-env.d.ts 38 | -------------------------------------------------------------------------------- /one-social-media/README.md: -------------------------------------------------------------------------------- 1 | This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | npm run dev 9 | # or 10 | yarn dev 11 | # or 12 | pnpm dev 13 | # or 14 | bun dev 15 | ``` 16 | 17 | Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. 18 | 19 | You can start editing the page by modifying `app/page.js`. The page auto-updates as you edit the file. 20 | 21 | This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font. 22 | 23 | ## Learn More 24 | 25 | To learn more about Next.js, take a look at the following resources: 26 | 27 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 28 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 29 | 30 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 31 | 32 | ## Deploy on Vercel 33 | 34 | The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. 35 | 36 | Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. 37 | -------------------------------------------------------------------------------- /one-social-media/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "paths": { 4 | "@/*": ["./src/*"] 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /one-social-media/next.config.mjs: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | const nextConfig = {}; 3 | 4 | export default nextConfig; 5 | -------------------------------------------------------------------------------- /one-social-media/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "one-social-media", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "next dev", 7 | "build": "next build", 8 | "start": "next start", 9 | "lint": "next lint" 10 | }, 11 | "dependencies": { 12 | "@emotion/react": "^11.11.3", 13 | "@emotion/styled": "^11.11.0", 14 | "@mui/icons-material": "^5.15.6", 15 | "@mui/material": "^5.15.6", 16 | "@tanstack/react-query": "^5.17.19", 17 | "@tanstack/react-query-devtools": "^5.17.21", 18 | "axios": "^1.6.6", 19 | "next": "14.1.0", 20 | "notistack": "^3.0.1", 21 | "react": "^18", 22 | "react-dom": "^18", 23 | "react-icons": "^5.0.1", 24 | "react-image-crop": "^11.0.5", 25 | "socket.io-client": "^4.7.4", 26 | "ws": "^8.16.0" 27 | }, 28 | "devDependencies": { 29 | "autoprefixer": "^10.0.1", 30 | "postcss": "^8", 31 | "tailwindcss": "^3.3.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /one-social-media/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /one-social-media/public/default_profile.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/default_profile.jpeg -------------------------------------------------------------------------------- /one-social-media/public/facebook.svg: -------------------------------------------------------------------------------- 1 | FBWordmark_Hex-RGB-1024 2 | -------------------------------------------------------------------------------- /one-social-media/public/hareesh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/hareesh.png -------------------------------------------------------------------------------- /one-social-media/public/home-hero.avif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/home-hero.avif -------------------------------------------------------------------------------- /one-social-media/public/next copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /one-social-media/public/next.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /one-social-media/public/osm-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/osm-white.png -------------------------------------------------------------------------------- /one-social-media/public/osm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/osm.png -------------------------------------------------------------------------------- /one-social-media/public/portFolio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/public/portFolio.png -------------------------------------------------------------------------------- /one-social-media/public/vercel copy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /one-social-media/public/vercel.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /one-social-media/src/app/Context/UserContest.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { createContext, useState } from "react"; 3 | export const UserContest = createContext(null); 4 | 5 | function PhotoContestProvider({ children }) { 6 | const [photo, setPhoto] = useState(0); 7 | const [activeStep, setActiveStep] = useState(0); 8 | return ( 9 | 17 | {children} 18 | 19 | ); 20 | } 21 | export default PhotoContestProvider; 22 | -------------------------------------------------------------------------------- /one-social-media/src/app/QueryProvider.js: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; 3 | import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; 4 | import { SnackbarProvider } from "notistack"; 5 | const queryClient = new QueryClient(); 6 | const QueryProvider = ({ children }) => { 7 | return ( 8 | 9 | 10 | {children} 11 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | export default QueryProvider; 18 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Avatar.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Avatar } from "@mui/material"; 3 | 4 | const AvatarBlock = ({ url, data }) => { 5 | return ( 6 | <> 7 |
8 |
9 | 10 |

11 | {data} 12 |

13 |
14 |
15 |
16 | 17 | ); 18 | }; 19 | 20 | export default AvatarBlock; 21 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Footer.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { footerLinks } from '../data/Data' 3 | const Footer = () => { 4 | const date = new Date; 5 | return ( 6 | 48 | ) 49 | } 50 | 51 | export default Footer 52 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/LogoPart.jsx: -------------------------------------------------------------------------------- 1 | import Image from "next/image"; 2 | const Leftpart = () => { 3 | return ( 4 |
5 |
6 |
7 | logo 12 |
13 |
14 |

15 | One social media helps you connect and share with the people in your 16 | life. 17 |

18 |
19 |
20 |
21 | ); 22 | }; 23 | export default Leftpart; 24 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/NavBar.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { FiMenu } from "react-icons/fi"; 4 | import { MdAccountCircle } from "react-icons/md"; 5 | import { adminData, deletePost, getUser, getUserPost } from "@/app/utils/api"; 6 | import Tooltip from "@mui/material/Tooltip"; 7 | import Fade from "@mui/material/Fade"; 8 | import Link from "next/link"; 9 | import { FaUserEdit } from "react-icons/fa"; 10 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 11 | import ProfileUpdate from "./homecomponents/Profile/profileUpdate"; 12 | import ProfileCard from "./homecomponents/Profile/ProfileCard"; 13 | import FriendRequest from "./homecomponents/FriendRequest"; 14 | import Suggestion from "./homecomponents/Suggestion"; 15 | import DeleteIcon from "@mui/icons-material/Delete"; 16 | import IconButton from "@mui/material/IconButton"; 17 | import FavoriteIcon from "@mui/icons-material/Favorite"; 18 | import CloseIcon from "@mui/icons-material/Close"; 19 | import { 20 | Avatar, 21 | DialogContent, 22 | Dialog, 23 | Drawer, 24 | AppBar, 25 | Toolbar, 26 | } from "@mui/material"; 27 | import axios from "axios"; 28 | import { useSnackbar } from "notistack"; 29 | 30 | const NavBar = () => { 31 | const [userid, setUserId] = useState(""); 32 | const [userWindow, setUserWindow] = useState(false); 33 | const [edit, setEdit] = useState(false); 34 | const [mini, setMini] = useState(false); 35 | const { enqueueSnackbar } = useSnackbar(); 36 | 37 | const onLogout = async () => { 38 | const res = await axios.post( 39 | `${process.env.NEXT_PUBLIC_BACKEND}/logout`, 40 | {}, 41 | { 42 | withCredentials: true, 43 | } 44 | ); 45 | if (res.status === 200) { 46 | localStorage.clear(); 47 | window.location.replace("/"); 48 | } 49 | }; 50 | 51 | //user 52 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 53 | const queryClient = useQueryClient(); 54 | 55 | const userWindowHandle = (id) => { 56 | setUserId(id); 57 | setUserWindow(true); 58 | mutate(); 59 | usePost.mutate(); 60 | }; 61 | 62 | const handleClose = () => { 63 | setUserWindow(false); 64 | setMini(false); 65 | }; 66 | const handleOpen = () => { 67 | setEdit(true); 68 | }; 69 | 70 | const { mutate, data: UserData } = useMutation({ 71 | mutationFn: () => getUser(userid), 72 | onSuccess: () => { 73 | queryClient.invalidateQueries({ queryKey: ["user"] }); 74 | }, 75 | }); 76 | 77 | let timestampStr = UserData?.DOB; 78 | let birthday; 79 | if (timestampStr) { 80 | let timestamp = new Date(timestampStr); 81 | birthday = timestamp.toISOString().split("T")[0]; 82 | } else { 83 | birthday = null; 84 | } 85 | 86 | // mini 87 | const handleChangeMini = () => { 88 | setMini(true); 89 | }; 90 | 91 | //delete 92 | 93 | const usePost = useMutation({ 94 | mutationFn: () => getUserPost(userid), 95 | onSuccess: () => { 96 | queryClient.invalidateQueries({ queryKey: ["userPost"] }); 97 | }, 98 | }); 99 | 100 | const deletepost = useMutation({ 101 | mutationFn: (userid) => deletePost(userid), 102 | onSuccess: (message) => { 103 | queryClient.invalidateQueries({ queryKey: ["post"] }); 104 | setUserWindow(false); 105 | if(message === "Delete SuccessFully"){ 106 | enqueueSnackbar(message,{ 107 | autoHideDuration: 2000, 108 | variant: "success", 109 | anchorOrigin: { 110 | vertical: "bottom", 111 | horizontal: "right", 112 | }, 113 | preventDuplicate: false, 114 | }); 115 | } 116 | else{ 117 | enqueueSnackbar(message, { 118 | autoHideDuration: 2000, 119 | variant: "error", 120 | anchorOrigin: { 121 | vertical: "bottom", 122 | horizontal: "right", 123 | }, 124 | preventDuplicate: false, 125 | }); 126 | } 127 | } 128 | }); 129 | 130 | const deletePostId = (id) => { 131 | deletepost.mutate(id); 132 | }; 133 | 134 | return ( 135 | 364 | ); 365 | }; 366 | 367 | export default NavBar; 368 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/Like.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { GoHeart, GoHeartFill } from "react-icons/go"; 3 | import { likeAPost, adminData } from "@/app/utils/api"; 4 | import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query"; 5 | 6 | function LikeDislike({ like, id }) { 7 | const queryClient = useQueryClient(); 8 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 9 | 10 | const mutation = useMutation({ 11 | mutationFn: likeAPost(id), 12 | onSuccess: () => { 13 | queryClient.invalidateQueries({ queryKey: ["post"] }); 14 | }, 15 | }); 16 | 17 | const handleLike = () => { 18 | mutation.mutate(); 19 | }; 20 | 21 | return ( 22 |
23 | {like.includes(Admin?._id) ? ( 24 |
25 | 30 |
31 | ) : ( 32 |
33 | 38 |
39 | )} 40 |
41 |

{like.length}

42 |
43 |
44 | ); 45 | } 46 | 47 | export default LikeDislike; 48 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/MakePost.jsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Dialog, DialogTitle, Typography, Box } from "@mui/material"; 3 | import IconButton from "@mui/material/IconButton"; 4 | import CloseIcon from "@mui/icons-material/Close"; 5 | import ImageCrop from "../imagecrop/crop"; 6 | import Stepper from "@mui/material/Stepper"; 7 | import Step from "@mui/material/Step"; 8 | import StepLabel from "@mui/material/StepLabel"; 9 | import { UserContest } from "../../Context/UserContest"; 10 | const MakePost = ({ open, setPostOpen, mode }) => { 11 | const context = useContext(UserContest); 12 | 13 | const handleClose = () => { 14 | setPostOpen(false); 15 | context.setActiveStep(0); 16 | }; 17 | 18 | const steps = ["DESCRIPTION", "UPLOAD FILE", "UPLOAD"]; 19 | 20 | if (context.activeStep === 3) { 21 | handleClose(); 22 | } 23 | 24 | return ( 25 | 31 |
32 | 39 | 43 | {mode} 44 | 45 | 46 | 47 | {steps.map((label) => ( 48 | 49 | 50 |

51 | {label} 52 |

53 |
54 |
55 | ))} 56 |
57 |
58 | 59 | 60 | 61 | 62 |
63 | 64 |
65 |
66 | ); 67 | }; 68 | 69 | export default MakePost; 70 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/Post.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { AiOutlineMenu } from "react-icons/ai"; 3 | import "../../globals.css"; 4 | import LikeDislike from "./Like"; 5 | import { 6 | deletePost, 7 | getAllPost, 8 | getUser, 9 | getUserPost, 10 | sendFriendRequestMod, 11 | } from "@/app/utils/api"; 12 | import Comment from "./comment/Comment"; 13 | import MakePost from "./MakePost"; 14 | import PostInput from "./PostInput"; 15 | import Backdrop from "@mui/material/Backdrop"; 16 | import CircularProgress from "@mui/material/CircularProgress"; 17 | import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; 18 | import axios from "axios"; 19 | import { FaUserPlus } from "react-icons/fa6"; 20 | import { MdOutlinePostAdd } from "react-icons/md"; 21 | import IconButton from "@mui/material/IconButton"; 22 | import CloseIcon from "@mui/icons-material/Close"; 23 | import FavoriteIcon from "@mui/icons-material/Favorite"; 24 | import { Dialog, DialogContent, AppBar, Toolbar } from "@mui/material"; 25 | import DeleteIcon from "@mui/icons-material/Delete"; 26 | 27 | const URL = process.env.NEXT_PUBLIC_BACKEND; 28 | 29 | const Post = () => { 30 | const [open, setOpen] = useState(false); 31 | const [postOpen, setPostOpen] = useState(false); 32 | const [id, setid] = useState(""); 33 | const [mode, setMode] = useState(""); 34 | const [userid, setUserId] = useState(""); 35 | const [userWindow, setUserWindow] = useState(false); 36 | const [showComponent, setShowComponent] = useState(""); 37 | const [friendRequestId, setFriendRequestId] = useState(); 38 | const newData = { requestId: friendRequestId }; 39 | 40 | const userWindowHandle = (id) => { 41 | setUserId(id); 42 | setUserWindow(true); 43 | mutate(); 44 | }; 45 | 46 | const handleClose = () => { 47 | setOpen(false); 48 | setUserWindow(false); 49 | }; 50 | const handleOpen = (id) => { 51 | setid(id); 52 | setOpen(true); 53 | usePost.mutate(id); 54 | }; 55 | 56 | const handlepostOpen = () => { 57 | setMode("MAKE POST"); 58 | setPostOpen(true); 59 | }; 60 | 61 | const handlepostClose = () => { 62 | setPostOpen(false); 63 | }; 64 | 65 | const { 66 | data: Post, 67 | isLoading: loading, 68 | isSuccess: success, 69 | } = useQuery({ queryKey: ["post"], queryFn: getAllPost }); 70 | 71 | const queryClient = useQueryClient(); 72 | 73 | const { mutate, data: UserData } = useMutation({ 74 | mutationFn: () => getUser(userid), 75 | onSuccess: () => { 76 | queryClient.invalidateQueries({ queryKey: ["user"] }); 77 | }, 78 | }); 79 | 80 | let timestampStr = UserData?.DOB; 81 | let birthday; 82 | if (timestampStr) { 83 | let timestamp = new Date(timestampStr); 84 | birthday = timestamp.toISOString().split("T")[0]; 85 | } else { 86 | birthday = null; 87 | } 88 | 89 | const searchUserResult = useMutation({ 90 | mutationKey: ["searchUserResult"], 91 | mutationFn: async (searchData) => { 92 | const response = await axios.post(`${URL}/searchUser`, { 93 | search: searchData, 94 | }); 95 | return response.data.data; 96 | }, 97 | }); 98 | 99 | const handleSearch = (e) => { 100 | setShowComponent(e.target.value); 101 | searchUserResult.mutate(e.target.value); 102 | }; 103 | 104 | //send request 105 | const mutation = useMutation({ 106 | mutationFn: () => sendFriendRequestMod(newData), 107 | onSuccess: () => { 108 | queryClient.invalidateQueries({ queryKey: ["suggestion"] }); 109 | }, 110 | }); 111 | 112 | const sendRequest = (id) => { 113 | setFriendRequestId(id); 114 | mutation.mutate(); 115 | }; 116 | 117 | const usePost = useMutation({ 118 | mutationFn: (newid) => getUserPost(newid), 119 | onSuccess: () => { 120 | queryClient.invalidateQueries({ queryKey: ["userPost"] }); 121 | }, 122 | }); 123 | 124 | const deletepost = useMutation({ 125 | mutationFn: (userid) => deletePost(userid), 126 | onSuccess: () => { 127 | queryClient.invalidateQueries({ queryKey: ["post"] }); 128 | setUserWindow(false); 129 | }, 130 | }); 131 | 132 | const deletePostId = (id) => { 133 | deletepost.mutate(id); 134 | }; 135 | 136 | return ( 137 |
138 |
139 |
140 | {!loading && ( 141 |
142 |
143 | 151 |
152 |
153 | 154 | 159 |

post

160 |
161 |
162 |
163 | {showComponent && ( 164 |
165 | {searchUserResult.data && ( 166 |
    167 | {searchUserResult.data 168 | .filter((user) => user.firstname.toLowerCase()) 169 | .map((user) => ( 170 |
  • 171 |
    userWindowHandle(user._id)} 174 | > 175 | {user.profileUrl ? ( 176 | 180 | ) : ( 181 | 185 | )} 186 |

    187 | {user.firstname + " " + user.lastname} 188 |

    189 |
    190 | 191 |
    192 | sendRequest(user._id)} 194 | /> 195 |
    196 |
  • 197 | ))} 198 |
199 | )} 200 |
201 | )} 202 |
203 | )} 204 |
205 |
206 |
207 | {Post?.map((users) => ( 208 |
209 |
userWindowHandle(users?.userId?._id)} 212 | > 213 |
214 | {users?.userId?.profileUrl ? ( 215 | 219 | ) : ( 220 | 224 | )} 225 |

226 | {users.userId.firstname + " " + users.userId.lastname} 227 |

228 |
229 |
230 | 231 |
232 |
233 |
234 | {users.image && ( 235 |
236 | { 238 | if (users.comments.length !== 0) { 239 | handleOpen(users._id); 240 | } 241 | }} 242 | className="flex justify-center items-center" 243 | src={users.image.url} 244 | alt="profile" 245 | /> 246 |
247 | )} 248 |
249 | 250 |
251 |
252 |

253 | 254 | {"@ " + 255 | users.userId.firstname + 256 | "_" + 257 | users.userId.lastname} 258 | 259 | 260 | {" " + users.description} 261 | 262 |

263 | {users.comments.length !== 0 && ( 264 |

handleOpen(users._id)} 267 | > 268 | View all {users.comments.length} comments .....{" "} 269 |

270 | )} 271 | 272 |
273 | 274 |
275 |
276 | ))} 277 |
278 |
279 | 280 | 281 | 282 |
283 | 284 | 285 |
286 |

287 | User data 288 |

289 | 294 | 295 | 296 |
297 |
298 |
299 | {UserData && ( 300 | <> 301 |
302 |
303 |
304 | {UserData.profileUrl ? ( 305 | 310 | ) : ( 311 | 316 | )} 317 |
318 |

319 | @ {UserData?.firstname + "_" + UserData?.lastname} 320 |

321 |
322 |
323 |
324 |

325 | {UserData.email} 326 |

327 |
328 |
329 |
330 |
331 |
332 |

location

333 |

{UserData.location}

334 |
335 |
336 |
337 |

profession

338 |

{UserData.profession}

339 |
340 |
341 |
342 |

date of birth

343 |

{birthday}

344 |
345 |
346 |
347 |

gender

348 |

{UserData.gender}

349 |
350 |
351 |
352 |
353 |
354 |
355 |

356 | posts 357 |

358 |
359 | {usePost.data && 360 | usePost.data.map((post) => ( 361 |
362 | 367 |
368 | deletePostId(post._id)} 371 | /> 372 |
373 | 374 |

375 | {post.likes.length} 376 |

377 |
378 |
379 |
380 | ))} 381 |
382 |
383 |
384 |

385 | friends 386 |

387 |
388 | {UserData.friends && 389 | UserData.friends.map((friend) => ( 390 |
userWindowHandle(friend._id)} 393 | > 394 | {friend.profileUrl ? ( 395 | 400 | ) : ( 401 | 407 | )} 408 |

409 | {"@ " + 410 | friend.firstname + 411 | "_" + 412 | friend.lastname} 413 |

414 |
415 | ))} 416 |
417 |
418 |
419 |
420 |
421 | 422 | )} 423 |
424 |
425 |
426 | 427 | theme.zIndex.drawer + 1 }} 429 | open={loading} 430 | onClick={success} 431 | > 432 | 433 | 434 |
435 |
436 | ); 437 | }; 438 | 439 | export default Post; 440 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/PostInput.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { LuSendHorizonal } from "react-icons/lu"; 3 | import { makeAComment } from "@/app/utils/api"; 4 | import { useMutation, useQueryClient } from "@tanstack/react-query"; 5 | 6 | const PostInput = ({ uid }) => { 7 | const [comment, setComment] = useState(""); 8 | const handleChangeComment = (e) => { 9 | setComment(e.target.value); 10 | }; 11 | const queryClient = useQueryClient(); 12 | const mutation = useMutation({ 13 | mutationFn: async () => { 14 | await makeAComment(comment, uid); 15 | }, 16 | onSuccess: () => { 17 | queryClient.invalidateQueries({ queryKey: ["post"] }); 18 | setComment(""); 19 | }, 20 | }); 21 | 22 | const postman = () => { 23 | mutation.mutate(); 24 | }; 25 | 26 | return ( 27 |
28 | { 35 | if (event.key === "Enter") postman(); 36 | }} 37 | onChange={handleChangeComment} 38 | /> 39 | {comment && ( 40 | 47 | )} 48 |
49 | ); 50 | }; 51 | 52 | export default PostInput; 53 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/comment/Comment.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Dialog, AppBar, Toolbar, Typography, Divider } from "@mui/material"; 3 | import IconButton from "@mui/material/IconButton"; 4 | import CloseIcon from "@mui/icons-material/Close"; 5 | import ListItemText from "@mui/material/ListItemText"; 6 | import ListItem from "@mui/material/ListItem"; 7 | import List from "@mui/material/List"; 8 | import AvatarBlock from "../../Avatar"; 9 | import { ReplyAvatarBlock } from "../../ReplyAvatar"; 10 | import CommentInput from "./CommentInput"; 11 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 12 | import { getAllPost, likeAcomment } from "@/app/utils/api"; 13 | import { SlLike } from "react-icons/sl"; 14 | 15 | const Comment = ({ open, setOpen, id }) => { 16 | const handleClose = () => { 17 | setOpen(false); 18 | }; 19 | 20 | const queryClient = useQueryClient(); 21 | const { data: Post } = useQuery({ queryKey: ["post"], queryFn: getAllPost }); 22 | const commentList = 23 | Post.find((item) => item._id === id && item.comments) || null; 24 | 25 | const mutation = useMutation({ 26 | mutationFn: (data) => likeAcomment(data), 27 | onSuccess: () => { 28 | queryClient.invalidateQueries({ queryKey: ["post"] }); 29 | }, 30 | }); 31 | 32 | const sendRequest = (id, rid) => { 33 | const data = { id, rid }; 34 | mutation.mutate(data); 35 | }; 36 | 37 | return ( 38 | <> 39 | {commentList !== null && ( 40 | 41 | 42 | 43 | 44 |
45 |

46 | Comments 47 |

48 | 49 | 50 | 51 |
52 |
53 |
54 |
55 |
56 |
57 | profile 58 |
59 |
60 | {commentList?.comments?.map((comments) => ( 61 | 62 | 63 |
64 | 73 | 81 | {comments.replies.map((result) => result.comment) && ( 82 |
83 | {comments?.replies?.map((repl) => ( 84 | <> 85 |
86 | {repl && ( 87 | <> 88 | 93 |

94 | {repl.comment} 95 |

96 |
97 |

98 | {repl.likes.length} likes{" "} 99 |

100 | 101 | 104 | sendRequest( 105 | comments._id, 106 | repl._id 107 | ) 108 | } 109 | /> 110 |
111 | 112 | )} 113 |
114 | 115 | ))} 116 | 117 |
118 | )} 119 |
120 |
121 |
122 | ))} 123 |
124 |
125 |
126 |
127 |
128 | )} 129 | 130 | ); 131 | }; 132 | 133 | export default Comment; 134 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/Post/comment/CommentInput.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { LuSendHorizonal } from "react-icons/lu"; 3 | import { adminData, replyCommentMod } from "@/app/utils/api"; 4 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 5 | 6 | const CommentInput = ({ uid }) => { 7 | const [comment, setComment] = useState(""); 8 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 9 | const url = Admin?.profileUrl?.url || "default_profile.jpeg"; 10 | const from = Admin?.firstname + " " + Admin?.lastname; 11 | 12 | const handleChangeComment = (e) => { 13 | setComment(e.target.value); 14 | }; 15 | 16 | const queryClient = useQueryClient(); 17 | const mutationReply = useMutation({ 18 | mutationFn: () => replyCommentMod(comment, from, url, uid), 19 | onSuccess: () => { 20 | queryClient.invalidateQueries({ queryKey: ["post"] }); 21 | setComment(""); 22 | }, 23 | }); 24 | 25 | const postman = () => { 26 | mutationReply.mutate(); 27 | }; 28 | 29 | return ( 30 | <> 31 |
32 | { 38 | if (event.key === "Enter") postman(); 39 | }} 40 | onChange={handleChangeComment} 41 | /> 42 | {comment && ( 43 | 51 | )} 52 |
53 | 54 | ); 55 | }; 56 | 57 | export default CommentInput; 58 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/ReplyAvatar.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | export const ReplyAvatarBlock = ({ url, data }) => { 4 | return ( 5 | <> 6 |
7 |
8 | 9 |

10 | {data} 11 |

12 |
13 |
14 |
15 | 16 | ); 17 | }; 18 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/FriendRequest.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { 4 | deletePost, 5 | friendRequestAcceptMode, 6 | friendRequestMode, 7 | getUser, 8 | getUserPost, 9 | } from "@/app/utils/api"; 10 | import { FaUserCheck } from "react-icons/fa6"; 11 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 12 | import IconButton from "@mui/material/IconButton"; 13 | import CloseIcon from "@mui/icons-material/Close"; 14 | import FavoriteIcon from "@mui/icons-material/Favorite"; 15 | import { Dialog, DialogContent, AppBar, Toolbar } from "@mui/material"; 16 | import DeleteIcon from "@mui/icons-material/Delete"; 17 | import { useSnackbar } from "notistack"; 18 | 19 | const FriendRequest = () => { 20 | const [id, setId] = useState(""); 21 | const newData = { rid: id, requestStatus: "Pending" }; 22 | const { enqueueSnackbar } = useSnackbar(); 23 | 24 | const { data: Request } = useQuery({ 25 | queryKey: ["friendRequest"], 26 | queryFn: friendRequestMode, 27 | }); 28 | const queryClient = useQueryClient(); 29 | 30 | const friendRequestMutation = useMutation({ 31 | mutationFn: () => friendRequestAcceptMode(newData), 32 | onSuccess: (message) => { 33 | queryClient.invalidateQueries({ queryKey: ["friendRequest"] }); 34 | queryClient.invalidateQueries({ queryKey: ["Admin"] }); 35 | enqueueSnackbar(message, { 36 | autoHideDuration: 3000, 37 | variant: "success", 38 | anchorOrigin: { 39 | vertical: "bottom", 40 | horizontal: "right", 41 | }, 42 | }); 43 | }, 44 | }); 45 | 46 | const readyToAccept = (id) => { 47 | setId(id); 48 | friendRequestMutation.mutate(); 49 | }; 50 | 51 | //user 52 | const [userid, setUserId] = useState(""); 53 | const [userWindow, setUserWindow] = useState(false); 54 | 55 | const userWindowHandle = (id) => { 56 | setUserId(id); 57 | setUserWindow(true); 58 | mutate(); 59 | usePost.mutate(id); 60 | }; 61 | 62 | const handleClose = () => { 63 | setUserWindow(false); 64 | }; 65 | 66 | const { mutate, data: UserData } = useMutation({ 67 | mutationFn: () => getUser(userid), 68 | onSuccess: () => { 69 | queryClient.invalidateQueries({ queryKey: ["user"] }); 70 | }, 71 | }); 72 | 73 | let timestampStr = UserData?.DOB; 74 | let birthday; 75 | if (timestampStr) { 76 | let timestamp = new Date(timestampStr); 77 | birthday = timestamp.toISOString().split("T")[0]; 78 | } else { 79 | birthday = null; 80 | } 81 | 82 | const usePost = useMutation({ 83 | mutationFn: (userid) => getUserPost(userid), 84 | onSuccess: () => { 85 | queryClient.invalidateQueries({ queryKey: ["userPost"] }); 86 | }, 87 | }); 88 | 89 | const deletepost = useMutation({ 90 | mutationFn: (userid) => deletePost(userid), 91 | onSuccess: () => { 92 | queryClient.invalidateQueries({ queryKey: ["post"] }); 93 | setUserWindow(false); 94 | }, 95 | }); 96 | 97 | const deletePostId = (id) => { 98 | deletepost.mutate(id); 99 | }; 100 | 101 | return ( 102 |
103 |

104 | Friend Request 105 |

106 |
107 |
108 |
109 | {Request && 110 | Request.map((friend) => ( 111 |
112 |
userWindowHandle(friend.requestFrom._id)} 115 | > 116 | {friend?.requestFrom?.profileUrl?.url ? ( 117 | 122 | ) : ( 123 | 128 | )} 129 |

130 | {friend.requestFrom.firstname + 131 | " " + 132 | friend.requestFrom.lastname} 133 |

134 |
135 |
136 | readyToAccept(friend._id)} /> 137 |
138 |
139 | ))} 140 |
141 |
142 |
143 | 144 | 145 |
146 | 147 | 148 |
149 |

150 | user Data 151 |

152 | 153 | 154 | 155 |
156 |
157 |
158 | {UserData && ( 159 | <> 160 |
161 |
162 |
163 | {UserData?.profileUrl?.url ? ( 164 | 169 | ) : ( 170 | 175 | )} 176 |
177 |

178 | @ {UserData?.firstname + "_" + UserData?.lastname} 179 |

180 |
181 |
182 |
183 |

184 | {UserData.email} 185 |

186 |
187 |
188 |
189 |
190 |
191 |

location

192 |

{UserData.location}

193 |
194 |
195 |
196 |

profession

197 |

{UserData.profession}

198 |
199 |
200 |
201 |

date of birth

202 |

{birthday}

203 |
204 |
205 |
206 |

gender

207 |

{UserData.gender}

208 |
209 |
210 |
211 |
212 |
213 |
214 |

215 | posts 216 |

217 |
218 | {usePost.data && 219 | usePost.data.map((post) => ( 220 |
221 | 226 |
227 | deletePostId(post._id)} 230 | /> 231 |
232 | 233 |

234 | {post.likes.length} 235 |

236 |
237 |
238 |
239 | ))} 240 |
241 |
242 | 243 |
244 |

245 | friends 246 |

247 |
248 | {UserData.friends && 249 | UserData.friends.map((friend) => ( 250 |
userWindowHandle(friend._id)} 253 | > 254 | {friend.profileUrl ? ( 255 | 260 | ) : ( 261 | 267 | )} 268 |

269 | {"@ " + 270 | friend.firstname + 271 | "_" + 272 | friend.lastname} 273 |

274 |
275 | ))} 276 |
277 |
278 |
279 |
280 |
281 | 282 | )} 283 |
284 |
285 |
286 |
287 | ); 288 | }; 289 | 290 | export default FriendRequest; 291 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Friends.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { FaUserXmark } from "react-icons/fa6"; 4 | import { adminData, deleteFriend, deletePost, getUser, getUserPost } from "@/app/utils/api"; 5 | import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; 6 | import IconButton from "@mui/material/IconButton"; 7 | import CloseIcon from "@mui/icons-material/Close"; 8 | import FavoriteIcon from "@mui/icons-material/Favorite"; 9 | import { Dialog, DialogContent, AppBar, Toolbar } from "@mui/material"; 10 | import DeleteIcon from "@mui/icons-material/Delete"; 11 | import { useSnackbar } from "notistack"; 12 | 13 | const Friends = () => { 14 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 15 | const friends = Admin?.friends; 16 | 17 | const [userid, setUserId] = useState(""); 18 | const [userWindow, setUserWindow] = useState(false); 19 | const { enqueueSnackbar } = useSnackbar(); 20 | 21 | const userWindowHandle = (id) => { 22 | setUserId(id); 23 | setUserWindow(true); 24 | mutate(); 25 | userPost.mutate(id); 26 | }; 27 | 28 | const handleClose = () => { 29 | setUserWindow(false); 30 | }; 31 | 32 | const queryClient = useQueryClient(); 33 | 34 | const { mutate, data: UserData } = useMutation({ 35 | mutationFn: () => getUser(userid), 36 | onSuccess: () => { 37 | queryClient.invalidateQueries({ queryKey: ["user"] }); 38 | }, 39 | }); 40 | 41 | let timestampStr = UserData?.DOB; 42 | let birthday; 43 | if (timestampStr) { 44 | let timestamp = new Date(timestampStr); 45 | birthday = timestamp.toISOString().split("T")[0]; 46 | } else { 47 | birthday = null; 48 | } 49 | 50 | const userPost = useMutation({ 51 | mutationFn: (userid) => getUserPost(userid), 52 | onSuccess: () => { 53 | queryClient.invalidateQueries({ queryKey: ["userPost"] }); 54 | }, 55 | }); 56 | 57 | const deletepost = useMutation({ 58 | mutationFn: (userid) => deletePost(userid), 59 | onSuccess: () => { 60 | queryClient.invalidateQueries({ queryKey: ["post"] }); 61 | setUserWindow(false); 62 | }, 63 | }); 64 | 65 | const deletePostId = (id) => { 66 | deletepost.mutate(id); 67 | }; 68 | 69 | const deletfriend = useMutation({ 70 | mutationFn: (userid) => deleteFriend(userid), 71 | onSuccess: (message) => { 72 | queryClient.invalidateQueries({ queryKey: ["Admin"] }); 73 | enqueueSnackbar(message,{ 74 | autoHideDuration: 2000, 75 | variant: "success", 76 | anchorOrigin: { 77 | vertical: "bottom", 78 | horizontal: "right", 79 | }, 80 | preventDuplicate: false, 81 | }); 82 | }, 83 | }); 84 | 85 | const deleteFriendCall=(id)=>{ 86 | deletfriend.mutate(id) 87 | } 88 | 89 | return ( 90 | <> 91 | { 92 |
93 |

94 | Friends 95 |

96 |
97 |
98 |
99 | {friends && 100 | friends.map((friend) => ( 101 |
102 |
userWindowHandle(friend._id)} 105 | > 106 | {friend.profileUrl ? ( 107 | 112 | ) : ( 113 | 118 | )} 119 | 120 |

121 | {friend.firstname}{" "} 122 | 123 | {friend.lastname} 124 | 125 |

126 |
127 |
128 | deleteFriendCall(friend._id)} /> 129 |
130 |
131 | ))} 132 |
133 |
134 |
135 |
136 | } 137 | 138 | 139 | 140 |
141 | 142 | 143 |
144 |

145 | user data 146 |

147 | 148 | 149 | 150 |
151 |
152 |
153 | {UserData && ( 154 | <> 155 |
156 |
157 |
158 | {UserData.profileUrl ? ( 159 | 164 | ) : ( 165 | 170 | )} 171 |
172 |

173 | @ {UserData?.firstname + "_" + UserData?.lastname} 174 |

175 |
176 |
177 |
178 |

179 | {UserData.email} 180 |

181 |
182 |
183 |
184 |
185 |
186 |

location

187 |

{UserData.location}

188 |
189 |
190 |
191 |

profession

192 |

{UserData.profession}

193 |
194 |
195 |
196 |

date of birth

197 |

{birthday}

198 |
199 |
200 |
201 |

gender

202 |

{UserData.gender}

203 |
204 |
205 |
206 |
207 |
208 |
209 |

210 | posts 211 |

212 |
213 | {userPost.data && 214 | userPost.data.map((post) => ( 215 |
216 | 221 |
222 | deletePostId(post._id)} 225 | /> 226 |
227 | 228 |

229 | {post.likes.length} 230 |

231 |
232 |
233 |
234 | ))} 235 |
236 |
237 | 238 |
239 |

240 | friends 241 |

242 |
243 | {UserData.friends && 244 | UserData.friends.map((friend) => ( 245 |
userWindowHandle(friend._id)} 248 | > 249 | {friend.profileUrl ? ( 250 | 255 | ) : ( 256 | 262 | )} 263 |

264 | {"@ " + 265 | friend.firstname + 266 | "_" + 267 | friend.lastname} 268 |

269 |
270 | ))} 271 |
272 |
273 |
274 |
275 |
276 | 277 | )} 278 |
279 |
280 |
281 | 282 | ); 283 | }; 284 | 285 | export default Friends; 286 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Profile/ProfileCard.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useContext } from "react"; 2 | import { MdOutlineEdit } from "react-icons/md"; 3 | import ProfilePhotoUpdate from "./ProfilePhotoUpdate"; 4 | import { UserContest } from "@/app/Context/UserContest"; 5 | import { adminData } from "@/app/utils/api"; 6 | import { useQuery } from "@tanstack/react-query"; 7 | import Tooltip from "@mui/material/Tooltip"; 8 | import Fade from "@mui/material/Fade"; 9 | import Backdrop from "@mui/material/Backdrop"; 10 | import CircularProgress from "@mui/material/CircularProgress"; 11 | 12 | const ProfileCard = () => { 13 | const [mode, setMode] = useState(""); 14 | const context = useContext(UserContest); 15 | 16 | const [profile, profileChange] = useState(false); 17 | 18 | const changeProfile = (e) => { 19 | e.preventDefault(); 20 | context.photoUpateType = "PROFILE UPDATE"; 21 | setMode("PROFILE UPDATE"); 22 | profileChange(true); 23 | }; 24 | 25 | const { 26 | data: Admin, 27 | isLoading: loading, 28 | isSuccess: success, 29 | } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 30 | return ( 31 | <> 32 |
33 |

34 | Admin 35 |

36 |
37 |
38 | {Admin && Admin?.profileUrl !== null ? ( 39 | 45 | 50 | 51 | ) : ( 52 | 57 | )} 58 | 59 | 60 | 61 |
62 | {Admin ? ( 63 |

64 | @ {Admin?.firstname + "_" + Admin?.lastname} 65 |

66 | ) : ( 67 |

68 | @ usernamae 69 |

70 | )} 71 |
72 |
73 |
74 | {Admin && Admin.location !== null ? ( 75 |
76 |

{Admin.location}

77 |
78 | ) : ( 79 |
80 |

Location

81 |
82 | )} 83 | {Admin && Admin.profession !== null ? ( 84 |
85 |

{Admin.profession}

86 |
87 | ) : ( 88 |
89 |

Profession

90 |
91 | )} 92 |
93 | 98 |
99 | theme.zIndex.drawer + 1 }} 101 | open={loading} 102 | onClick={success} 103 | > 104 | 105 | 106 |
107 | 108 | ); 109 | }; 110 | 111 | export default ProfileCard; 112 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Profile/ProfilePhotoUpdate.jsx: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { Dialog, DialogContent, DialogTitle, Typography } from "@mui/material"; 3 | import React from "react"; 4 | import ImageCrop from "../../imagecrop/crop"; 5 | import IconButton from "@mui/material/IconButton"; 6 | import CloseIcon from "@mui/icons-material/Close"; 7 | import { Box } from "@mui/material"; 8 | import { UserContest } from "../../../Context/UserContest"; 9 | import Stepper from "@mui/material/Stepper"; 10 | import Step from "@mui/material/Step"; 11 | import StepLabel from "@mui/material/StepLabel"; 12 | import { adminData } from "@/app/utils/api"; 13 | import { useQuery, useQueryClient } from "@tanstack/react-query"; 14 | 15 | const ProfilePhotoUpdate = ({ open, setOpen, mode }) => { 16 | const context = useContext(UserContest); 17 | const queryClient = useQueryClient(); 18 | const handleClose = () => { 19 | setOpen(false); 20 | }; 21 | 22 | const steps = ["UPLOAD FILE", "UPLOAD"]; 23 | 24 | if (context.activeStep === 3) { 25 | handleClose(); 26 | } 27 | 28 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 29 | 30 | return ( 31 | <> 32 |
33 | 34 |
35 | 42 |

{mode}

43 | 44 | 45 | {steps.map((label) => ( 46 | 47 | 48 |

49 | {label} 50 |

51 |
52 |
53 | ))} 54 |
55 |
56 | 57 | 58 | 59 |
60 | {Admin && Admin?.profileUrl !== null ? ( 61 | 66 | ) : ( 67 | 72 | )} 73 | 74 | 75 | 76 | 77 | 78 |
79 |
80 |
81 | 82 | ); 83 | }; 84 | 85 | export default ProfilePhotoUpdate; 86 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Profile/ViewProfile.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { 3 | Dialog, 4 | DialogTitle, 5 | DialogContent, 6 | DialogActions, 7 | Typography, 8 | Divider, 9 | Box, 10 | } from "@mui/material"; 11 | import Input from "@/app/components/Input"; 12 | import { useQuery } from "@tanstack/react-query"; 13 | import { adminData } from "@/app/utils/api"; 14 | 15 | const ViewProfile = ({ open, setOpen }) => { 16 | const { data } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 17 | const Admin = data; 18 | 19 | const viewClose = () => { 20 | setOpen(false); 21 | }; 22 | 23 | return ( 24 |
25 | 26 | 27 | 28 | User Data 29 | 30 | It's quick and easy. 31 | 32 | 33 | 34 | 35 | onValue(e)} 42 | /> 43 | onValue(e)} 50 | /> 51 | 52 | 53 | 61 | onValue(e)} 67 | /> 68 | 69 | Date of birth ? 70 | onValue(e)} 75 | /> 76 | Gender ? 77 | 78 | 87 | 96 | 105 | 106 | 107 | 110 | 117 | 118 | 119 |
120 | ); 121 | }; 122 | 123 | export default ViewProfile; 124 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Profile/profileUpdate.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { adminData, updateUser } from "@/app/utils/api"; 4 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 5 | import CloseIcon from "@mui/icons-material/Close"; 6 | import IconButton from "@mui/material/IconButton"; 7 | import { AppBar, Toolbar } from "@mui/material"; 8 | 9 | const ProfileUpdate = ({ setEdit }) => { 10 | const { data: Admin } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 11 | 12 | const pageData = { 13 | firstname: "", 14 | lastname: "", 15 | DOB: "", 16 | gender: "", 17 | profession: "", 18 | location: "", 19 | }; 20 | 21 | const [pagedata, setpage] = useState(pageData); 22 | const queryClient = useQueryClient(); 23 | 24 | const onValue = (e) => { 25 | e.preventDefault(); 26 | setpage({ ...pagedata, [e.target.name]: e.target.value }); 27 | }; 28 | 29 | const { mutate } = useMutation({ 30 | mutationFn: (pagedata) => updateUser(pagedata), 31 | onSuccess: () => { 32 | setEdit(false); 33 | queryClient.invalidateQueries(["Admin"]); 34 | }, 35 | }); 36 | 37 | const onpage = (e) => { 38 | mutate(pagedata); 39 | }; 40 | 41 | return ( 42 |
43 | 44 | 45 |
46 |

47 | Admin Data 48 |

49 | setEdit(false)} 53 | > 54 | 55 | 56 |
57 |
58 |
59 | {Admin && ( 60 |
61 |

Update

62 |
63 | onValue(e)} 70 | /> 71 | onValue(e)} 78 | /> 79 | onValue(e)} 86 | /> 87 | onValue(e)} 94 | /> 95 |
96 | 97 |
98 |

Date of birth ?

99 | onValue(e)} 106 | /> 107 |
108 | 109 |
110 |

Gender ?

111 | 121 |
122 |
123 |
{ 126 | setEdit(false); 127 | }} 128 | > 129 | cancle 130 |
131 | 132 | 139 |
140 |
141 | )} 142 |
143 | ); 144 | }; 145 | 146 | export default ProfileUpdate; 147 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/Suggestion.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import React, { useState } from "react"; 3 | import { FaUserPlus } from "react-icons/fa6"; 4 | import { 5 | deletePost, 6 | getUser, 7 | getUserPost, 8 | sendFriendRequestMod, 9 | suggestionMode, 10 | } from "@/app/utils/api"; 11 | import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; 12 | import IconButton from "@mui/material/IconButton"; 13 | import CloseIcon from "@mui/icons-material/Close"; 14 | import DeleteIcon from "@mui/icons-material/Delete"; 15 | import FavoriteIcon from "@mui/icons-material/Favorite"; 16 | import { Dialog, DialogContent, AppBar, Toolbar } from "@mui/material"; 17 | import { useSnackbar } from "notistack"; 18 | 19 | const Suggestion = () => { 20 | const queryClient = useQueryClient(); 21 | const { data: SuggestionData } = useQuery({ 22 | queryKey: ["suggestion"], 23 | queryFn: suggestionMode, 24 | }); 25 | 26 | const { enqueueSnackbar } = useSnackbar(); 27 | 28 | const RequestMutation = useMutation({ 29 | mutationFn: (newData) => sendFriendRequestMod(newData), 30 | onSuccess: (message) => { 31 | queryClient.invalidateQueries({ queryKey: ["suggestion"] }); 32 | if (message === "Sent Request") { 33 | enqueueSnackbar(message, { 34 | autoHideDuration: 3000, 35 | variant: "success", 36 | anchorOrigin: { 37 | vertical: "bottom", 38 | horizontal: "right", 39 | }, 40 | }); 41 | } else { 42 | enqueueSnackbar(message, { 43 | autoHideDuration: 3000, 44 | variant: "error", 45 | anchorOrigin: { 46 | vertical: "bottom", 47 | horizontal: "right", 48 | }, 49 | preventDuplicate: false, 50 | }); 51 | } 52 | }, 53 | }); 54 | 55 | const sendRequest = (id) => { 56 | const newData = { requestId: id }; 57 | RequestMutation.mutate(newData); 58 | // const newMessage = RequestMutation.data; 59 | // if (newMessage === undefined) { 60 | // enqueueSnackbar("Send Request Success", { 61 | // autoHideDuration: 3000, 62 | // variant: "success", 63 | // anchorOrigin: { 64 | // vertical: "bottom", 65 | // horizontal: "right", 66 | // }, 67 | // }); 68 | // } else { 69 | // enqueueSnackbar(newMessage, { 70 | // autoHideDuration: 3000, 71 | // variant: "error", 72 | // anchorOrigin: { 73 | // vertical: "bottom", 74 | // horizontal: "right", 75 | // }, 76 | // preventDuplicate: false, 77 | // }); 78 | // } 79 | }; 80 | 81 | //user 82 | 83 | const [userid, setUserId] = useState(""); 84 | const [userWindow, setUserWindow] = useState(false); 85 | 86 | const userWindowHandle = (id) => { 87 | setUserId(id); 88 | setUserWindow(true); 89 | mutate(); 90 | usePost.mutate(); 91 | }; 92 | 93 | const handleClose = () => { 94 | setUserWindow(false); 95 | }; 96 | const { mutate, data: UserData } = useMutation({ 97 | mutationFn: () => getUser(userid), 98 | onSuccess: () => { 99 | queryClient.invalidateQueries({ queryKey: ["user"] }); 100 | }, 101 | }); 102 | 103 | let timestampStr = UserData?.DOB; 104 | let birthday; 105 | if (timestampStr) { 106 | let timestamp = new Date(timestampStr); 107 | birthday = timestamp.toISOString().split("T")[0]; 108 | } else { 109 | birthday = null; 110 | } 111 | 112 | //get user 113 | const usePost = useMutation({ 114 | mutationFn: () => getUserPost(userid), 115 | onSuccess: () => { 116 | queryClient.invalidateQueries({ queryKey: ["userPost"] }); 117 | }, 118 | }); 119 | 120 | const deletepost = useMutation({ 121 | mutationFn: (userid) => deletePost(userid), 122 | onSuccess: () => { 123 | queryClient.invalidateQueries({ queryKey: ["post"] }); 124 | setUserWindow(false); 125 | }, 126 | }); 127 | 128 | const deletePostId = (id) => { 129 | deletepost.mutate(id); 130 | }; 131 | 132 | return ( 133 |
134 |

135 | Suggestion 136 |

137 |
138 |
139 |
140 | {SuggestionData?.map((friend) => ( 141 |
142 |
userWindowHandle(friend._id)} 145 | > 146 | {friend.profileUrl ? ( 147 | 152 | ) : ( 153 | 158 | )} 159 |

160 | {friend.firstname}{" "} 161 | 162 | {friend.lastname} 163 | 164 |

165 |
166 | 167 |
168 | sendRequest(friend._id)} /> 169 |
170 |
171 | ))} 172 |
173 |
174 |
175 | 176 | 177 | 178 |
179 | 180 | 181 |
182 |

183 | user Data 184 |

185 | 186 | 187 | 188 |
189 |
190 |
191 | {UserData && ( 192 | <> 193 |
194 |
195 |
196 | {UserData.profileUrl ? ( 197 | 202 | ) : ( 203 | 208 | )} 209 |
210 |

211 | @ {UserData?.firstname + "_" + UserData?.lastname} 212 |

213 |
214 |
215 |
216 |

217 | {UserData.email} 218 |

219 |
220 |
221 |
222 |
223 |
224 |

location

225 |

{UserData.location}

226 |
227 |
228 |
229 |

profession

230 |

{UserData.profession}

231 |
232 |
233 |
234 |

date of birth

235 |

{birthday}

236 |
237 |
238 |
239 |

gender

240 |

{UserData.gender}

241 |
242 |
243 |
244 |
245 |
246 |
247 |

248 | posts 249 |

250 |
251 | {usePost.data && 252 | usePost.data.map((post) => ( 253 |
254 | 259 |
260 | deletePostId(post._id)} 263 | /> 264 |
265 | 266 |

267 | {post.likes.length} 268 |

269 |
270 |
271 |
272 | ))} 273 |
274 |
275 | 276 |
277 |

278 | friends 279 |

280 |
281 | {UserData.friends && 282 | UserData.friends.map((friend) => ( 283 |
userWindowHandle(friend._id)} 286 | > 287 | {friend.profileUrl? ( 288 | 293 | ) : ( 294 | 300 | )} 301 |

302 | {"@ " + 303 | friend.firstname + 304 | "_" + 305 | friend.lastname} 306 |

307 |
308 | ))} 309 |
310 |
311 |
312 |
313 |
314 | 315 | )} 316 |
317 |
318 |
319 |
320 | ); 321 | }; 322 | 323 | export default Suggestion; 324 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/homecomponents/message.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Link from 'next/link' 3 | 4 | const Message = () => { 5 | return ( 6 | 7 |
8 | 14 |
15 | 16 | ); 17 | }; 18 | 19 | export default Message; 20 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/imagecrop/canvasPreview.jsx: -------------------------------------------------------------------------------- 1 | const TO_RADIANS = Math.PI / 180; 2 | 3 | export async function canvasPreview( 4 | image, 5 | canvas, 6 | crop, 7 | scale = 1, 8 | rotate = 0 9 | ) { 10 | const ctx = canvas.getContext("2d"); 11 | 12 | if (!ctx) { 13 | throw new Error("No 2d context"); 14 | } 15 | 16 | const scaleX = image.naturalWidth / image.width; 17 | const scaleY = image.naturalHeight / image.height; 18 | const pixelRatio = window.devicePixelRatio; 19 | canvas.width = Math.floor(crop.width * scaleX * pixelRatio); 20 | canvas.height = Math.floor(crop.height * scaleY * pixelRatio); 21 | 22 | ctx.scale(pixelRatio, pixelRatio); 23 | ctx.imageSmoothingQuality = "high"; 24 | 25 | const cropX = crop.x * scaleX; 26 | const cropY = crop.y * scaleY; 27 | 28 | const rotateRads = rotate * TO_RADIANS; 29 | const centerX = image.naturalWidth / 2; 30 | const centerY = image.naturalHeight / 2; 31 | ctx.save(); 32 | ctx.translate(-cropX, -cropY); 33 | ctx.translate(centerX, centerY); 34 | ctx.rotate(rotateRads); 35 | ctx.scale(scale, scale); 36 | ctx.translate(-centerX, -centerY); 37 | ctx.drawImage( 38 | image, 39 | 0, 40 | 0, 41 | image.naturalWidth, 42 | image.naturalHeight, 43 | 0, 44 | 0, 45 | image.naturalWidth, 46 | image.naturalHeight 47 | ); 48 | ctx.restore(); 49 | } 50 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/imagecrop/crop.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import axios from "axios"; 3 | import React, { useState, useRef, useContext } from "react"; 4 | import ReactCrop, { centerCrop, makeAspectCrop } from "react-image-crop"; 5 | import { canvasPreview } from "./canvasPreview"; 6 | import { useDebounceEffect } from "./useDebounceEffect"; 7 | import "react-image-crop/dist/ReactCrop.css"; 8 | import { UserContest } from "@/app/Context/UserContest"; 9 | import { styled } from "@mui/material/styles"; 10 | import Button from "@mui/material/Button"; 11 | import { Box } from "@mui/material"; 12 | import CloudUploadIcon from "@mui/icons-material/CloudUpload"; 13 | import Slider from "@mui/material/Slider"; 14 | import Backdrop from "@mui/material/Backdrop"; 15 | import CircularProgress from "@mui/material/CircularProgress"; 16 | import { useSnackbar } from "notistack"; 17 | import { useQueryClient,useMutation } from "@tanstack/react-query"; 18 | import { makeApost, profileUpdate } from "@/app/utils/api"; 19 | 20 | function centerAspectCrop(mediaWidth, mediaHeight, aspect) { 21 | return centerCrop( 22 | makeAspectCrop( 23 | { 24 | unit: "%", 25 | width: 90, 26 | }, 27 | aspect, 28 | mediaWidth, 29 | mediaHeight 30 | ), 31 | mediaWidth, 32 | mediaHeight 33 | ); 34 | } 35 | 36 | export default function ImageCrop({ mode }) { 37 | const [imgSrc, setImgSrc] = useState(""); 38 | const previewCanvasRef = useRef(null); 39 | const imgRef = useRef(null); 40 | const [crop, setCrop] = useState(); 41 | const [completedCrop, setCompletedCrop] = useState(); 42 | const [scale, setScale] = useState(1); 43 | const [rotate, setRotate] = useState(0); 44 | const [aspect, setAspect] = useState(1 / 1); 45 | const [loading, setLoading] = useState(false); 46 | const [description, setDescription] = useState(""); 47 | 48 | const queryClient = useQueryClient(); 49 | const context = useContext(UserContest); 50 | const { enqueueSnackbar } = useSnackbar(); 51 | 52 | const handleOnChange = (e) => { 53 | setDescription(e.target.value); 54 | }; 55 | 56 | const handleSteps = () => { 57 | context.setActiveStep(1); 58 | }; 59 | 60 | function onSelectFile(e) { 61 | if (e.target.files && e.target.files.length > 0) { 62 | setCrop(undefined); 63 | const reader = new FileReader(); 64 | reader.addEventListener("load", () => 65 | setImgSrc(reader.result?.toString() || "") 66 | ); 67 | reader.readAsDataURL(e.target.files[0]); 68 | context.setActiveStep(1); 69 | } 70 | } 71 | 72 | function onImageLoad(e) { 73 | if (aspect) { 74 | const { width, height } = e.currentTarget; 75 | setCrop(centerAspectCrop(width, height, aspect)); 76 | } 77 | } 78 | 79 | const profile = useMutation({ 80 | mutationFn:(data)=> profileUpdate(data), 81 | onSuccess: () => { 82 | queryClient.invalidateQueries({ queryKey: ["Admin"] }); 83 | context.setActiveStep(3); 84 | enqueueSnackbar("Peofile updated", { 85 | autoHideDuration: 3000, 86 | variant: "success", 87 | anchorOrigin: { 88 | vertical: "bottom", 89 | horizontal: "center", 90 | }, 91 | }); 92 | }, 93 | }); 94 | 95 | const post = useMutation({ 96 | mutationFn: (data)=> makeApost(description,data), 97 | onSuccess: () => { 98 | queryClient.invalidateQueries({ queryKey: ["post"] }); 99 | context.setActiveStep(3); 100 | enqueueSnackbar("Added a new Post", { 101 | autoHideDuration: 3000, 102 | variant: "success", 103 | anchorOrigin: { 104 | vertical: "bottom", 105 | horizontal: "center", 106 | }, 107 | }); 108 | }, 109 | }); 110 | 111 | async function onDownloadCropClick() { 112 | handleOpenLoading(); 113 | const image = imgRef.current; 114 | const previewCanvas = previewCanvasRef.current; 115 | if (!image || !previewCanvas || !completedCrop) { 116 | throw new Error("Crop canvas does not exist"); 117 | } 118 | const scaleX = image.naturalWidth / image.width; 119 | const scaleY = image.naturalHeight / image.height; 120 | 121 | const offscreen = new OffscreenCanvas( 122 | completedCrop.width * scaleX, 123 | completedCrop.height * scaleY 124 | ); 125 | const ctx = offscreen.getContext("2d"); 126 | if (!ctx) { 127 | throw new Error("No 2d context"); 128 | } 129 | 130 | ctx.drawImage( 131 | previewCanvas, 132 | 0, 133 | 0, 134 | previewCanvas.width, 135 | previewCanvas.height, 136 | 0, 137 | 0, 138 | offscreen.width, 139 | offscreen.height 140 | ); 141 | 142 | const blob = await offscreen.convertToBlob({ 143 | type: "image/png", 144 | }); 145 | 146 | const date = Date.now(); 147 | const imagename = `photo${date}`; 148 | 149 | const file = new File([blob], imagename, { 150 | type: "image/png", 151 | }); 152 | 153 | const formData = new FormData(); 154 | formData.append("file", file); 155 | formData.append("upload_preset", "SocilaMedia"); 156 | try { 157 | const response = await axios.post( 158 | `https://api.cloudinary.com/v1_1/sociladb/image/upload`, 159 | formData 160 | ); 161 | if (response.status == 200) { 162 | const url = response.data.url; 163 | const public_id = response.data.public_id; 164 | const data = { url, public_id }; 165 | try { 166 | if (mode !== "MAKE POST") { 167 | profile.mutate(data); 168 | } else { 169 | post.mutate(data); 170 | } 171 | } catch (error) { 172 | enqueueSnackbar(error.message, { 173 | autoHideDuration: 3000, 174 | variant: "error", 175 | anchorOrigin: { 176 | vertical: "bottom", 177 | horizontal: "center", 178 | }, 179 | }); 180 | } 181 | } 182 | } catch (error) { 183 | enqueueSnackbar(error.response.data.error.message, { 184 | autoHideDuration: 3000, 185 | variant: "error", 186 | anchorOrigin: { 187 | vertical: "bottom", 188 | horizontal: "center", 189 | }, 190 | }); 191 | } 192 | handleLoading(); 193 | } 194 | 195 | useDebounceEffect( 196 | async () => { 197 | if ( 198 | completedCrop?.width && 199 | completedCrop?.height && 200 | imgRef.current && 201 | previewCanvasRef.current 202 | ) { 203 | canvasPreview( 204 | imgRef.current, 205 | previewCanvasRef.current, 206 | completedCrop, 207 | scale, 208 | rotate 209 | ); 210 | } 211 | }, 212 | 100, 213 | [completedCrop, scale, rotate] 214 | ); 215 | 216 | const VisuallyHiddenInput = styled("input")({ 217 | clip: "rect(0 0 0 0)", 218 | clipPath: "inset(50%)", 219 | height: 1, 220 | overflow: "hidden", 221 | position: "absolute", 222 | bottom: 0, 223 | left: 0, 224 | whiteSpace: "nowrap", 225 | width: 1, 226 | }); 227 | 228 | //loading 229 | const handleLoading = () => { 230 | setLoading(false); 231 | }; 232 | const handleOpenLoading = () => { 233 | setLoading(true); 234 | }; 235 | 236 | return ( 237 |
238 | {mode === "MAKE POST" && ( 239 |
240 | 249 |
250 | )} 251 |
252 |
253 |
254 | 263 |
264 | 265 | {!!imgSrc && ( 266 |
267 | setCrop(percentCrop)} 270 | onComplete={(c) => setCompletedCrop(c)} 271 | aspect={aspect} 272 | minHeight={100} 273 | className="outline outline-2 outline-offset-2" 274 | > 275 | Crop me 283 | 284 |
285 | )} 286 | 287 | {!!completedCrop && ( 288 |
289 |
290 | 294 |
295 | {/* new */} 296 |
297 | 298 | setScale(Number(e.target.value))} 309 | /> 310 | 311 |
312 | 313 |
314 | 315 | 328 | setRotate( 329 | Math.min(180, Math.max(-180, Number(e.target.value))) 330 | ) 331 | } 332 | /> 333 | 334 |
335 |
336 | 343 |
344 |
345 | )} 346 |
347 | 348 | theme.zIndex.drawer + 1 }} 350 | open={loading} 351 | onClick={handleLoading} 352 | > 353 | 354 | 355 |
356 |
357 | ); 358 | } 359 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/imagecrop/useDebounceEffect.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect, DependencyList } from "react"; 2 | 3 | export function useDebounceEffect(fn, waitTime, deps) { 4 | useEffect(() => { 5 | const t = setTimeout(() => { 6 | fn.apply(deps); 7 | }, waitTime); 8 | 9 | return () => { 10 | clearTimeout(t); 11 | }; 12 | }, deps); 13 | } 14 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/login/Main.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import { useState } from "react"; 3 | import { 4 | Dialog, 5 | DialogTitle, 6 | DialogContent, 7 | DialogActions, 8 | Typography, 9 | Divider, 10 | Box, 11 | } from "@mui/material"; 12 | import axios from "axios"; 13 | import Backdrop from "@mui/material/Backdrop"; 14 | import CircularProgress from "@mui/material/CircularProgress"; 15 | import { useSnackbar } from "notistack"; 16 | 17 | const Home = () => { 18 | const APP_URL = process.env.NEXT_PUBLIC_BACKEND; 19 | const { enqueueSnackbar } = useSnackbar(); 20 | const loginData = { email: "", password: "" }; 21 | const registerData = { 22 | firstname: "", 23 | lastname: "", 24 | email: "", 25 | password: "", 26 | DOB: "", 27 | gender: "", 28 | }; 29 | 30 | const [logindata, setloginData] = useState(loginData); 31 | const [registerdata, setRegister] = useState(registerData); 32 | const [loading, setLoading] = useState(false); 33 | const [open, setOpen] = useState(false); 34 | const [passwordResetRequest, setPasswordResetRequest] = useState(false); 35 | const [resetEmail, setResetEmail] = useState(""); 36 | 37 | const onValueChange = (e) => { 38 | e.preventDefault(); 39 | setloginData({ ...logindata, [e.target.name]: e.target.value }); 40 | }; 41 | 42 | const onValue = (e) => { 43 | e.preventDefault(); 44 | setRegister({ ...registerdata, [e.target.name]: e.target.value }); 45 | }; 46 | 47 | const onRegister = async () => { 48 | handleOpenLoading(); 49 | try { 50 | const result = await axios.post(APP_URL + "/register", registerdata); 51 | if (result?.message === "Authentication failed") { 52 | localStorage.removeItem("user"); 53 | window.alert("user session expair Login again. "); 54 | window.location.replace("/"); 55 | } 56 | if (result.status === 200) { 57 | setRegister(registerData); 58 | enqueueSnackbar(result.data.message, { 59 | autoHideDuration: 2000, 60 | variant: "success", 61 | anchorOrigin: { 62 | vertical: "bottom", 63 | horizontal: "right", 64 | }, 65 | preventDuplicate: false, 66 | }); 67 | } else { 68 | enqueueSnackbar(result.data.message, { 69 | autoHideDuration: 2000, 70 | variant: "error", 71 | anchorOrigin: { 72 | vertical: "bottom", 73 | horizontal: "right", 74 | }, 75 | preventDuplicate: false, 76 | }); 77 | } 78 | 79 | handleLoading(); 80 | setOpen(false); 81 | } catch (error) { 82 | handleLoading(); 83 | enqueueSnackbar(result.data.message, { 84 | autoHideDuration: 2000, 85 | variant: "error", 86 | anchorOrigin: { 87 | vertical: "bottom", 88 | horizontal: "right", 89 | }, 90 | preventDuplicate: false, 91 | }); 92 | } 93 | }; 94 | 95 | const onLogin = async () => { 96 | handleOpenLoading(); 97 | try { 98 | const result = await axios.post(APP_URL + "/login", logindata,{ 99 | withCredentials:true 100 | }); 101 | if (result.status === 200) { 102 | localStorage.setItem("user", result.data.data); 103 | setloginData(loginData); 104 | window.location.replace("/home"); 105 | handleLoading(); 106 | } else { 107 | handleLoading(); 108 | enqueueSnackbar(result.data.message, { 109 | autoHideDuration: 2000, 110 | variant: "error", 111 | anchorOrigin: { 112 | vertical: "bottom", 113 | horizontal: "right", 114 | }, 115 | preventDuplicate: false, 116 | }); 117 | } 118 | } catch (error) { 119 | handleLoading(); 120 | } 121 | }; 122 | 123 | const dummyLogin = async (e) => { 124 | handleOpenLoading(); 125 | const data = { 126 | email: "test@gmail.com", 127 | password: "password", 128 | }; 129 | try { 130 | const result = await axios.post(APP_URL + "/login", data, { 131 | withCredentials: true, 132 | }); 133 | 134 | if (result.status === 200) { 135 | localStorage.setItem("user", result.data.data); 136 | window.location.replace("/home"); 137 | handleLoading(); 138 | } else { 139 | handleClick(); 140 | handleLoading(); 141 | } 142 | } catch (error) { 143 | handleLoading(); 144 | } 145 | }; 146 | 147 | const passwordRequest = async () => { 148 | handleOpenLoading(); 149 | if (resetEmail) { 150 | const response = await axios.post( 151 | APP_URL + "/user/password-reset-request", 152 | { email: resetEmail } 153 | ); 154 | if (response.status === 200) { 155 | onHadlepasswordResetRequestClose(); 156 | enqueueSnackbar(response.data.message, { 157 | autoHideDuration: 2000, 158 | variant: "success", 159 | anchorOrigin: { 160 | vertical: "bottom", 161 | horizontal: "right", 162 | }, 163 | preventDuplicate: false, 164 | }); 165 | } else { 166 | enqueueSnackbar(response.data.message, { 167 | autoHideDuration: 2000, 168 | variant: "error", 169 | anchorOrigin: { 170 | vertical: "bottom", 171 | horizontal: "right", 172 | }, 173 | preventDuplicate: false, 174 | }); 175 | } 176 | handleLoading(); 177 | } 178 | }; 179 | 180 | const handleClose = () => { 181 | setOpen(false); 182 | }; 183 | const handleOpen = (e) => { 184 | e.preventDefault(); 185 | setOpen(true); 186 | }; 187 | 188 | const handleLoading = () => { 189 | setLoading(false); 190 | }; 191 | 192 | const handleOpenLoading = () => { 193 | setLoading(true); 194 | }; 195 | 196 | const onHadlepasswordResetRequest = () => { 197 | setPasswordResetRequest(true); 198 | }; 199 | 200 | const onHadlepasswordResetRequestClose = () => { 201 | setPasswordResetRequest(false); 202 | }; 203 | 204 | return ( 205 |
206 |
207 |
208 | { 212 | if (event.key === "Enter") onLogin(); 213 | }} 214 | value={logindata.email} 215 | placeholder="Email Address" 216 | className="w-full border p-2 border-gray-400 text-white bg-black rounded-md focus:outline-none focus:ring-1 ring-white my-2" 217 | onChange={(e) => onValueChange(e)} 218 | /> 219 | { 223 | if (event.key === "Enter") onLogin(); 224 | }} 225 | value={logindata.password} 226 | placeholder="Password" 227 | className="w-full border p-2 border-gray-400 text-white bg-black rounded-md focus:outline-none focus:border-white my-2" 228 | onChange={(e) => onValueChange(e)} 229 | /> 230 |
231 | 238 | 239 | 246 |
247 | 254 |
255 |
256 | 263 |
264 |
265 |
266 |
267 |

268 | {" "} 269 | Create a Page for a celebrity, 270 | brand or business. 271 |

272 |
273 | 274 | 275 |
276 | 277 | 281 | Sign Up 282 | 283 | It's quick and easy. 284 | 285 | 286 | 287 | 288 | onValue(e)} 296 | /> 297 | onValue(e)} 305 | /> 306 | 307 | 308 | onValue(e)} 316 | /> 317 | onValue(e)} 324 | /> 325 | 326 | Date of birth ? 327 | onValue(e)} 333 | /> 334 | 335 |
336 | Gender ? 337 | 354 |
355 |
356 | 359 | 366 | 367 |
368 |
369 | 370 | 371 |
372 | 373 | 377 |

378 | Password Reset 379 |

380 |
381 |
382 | 383 | { 391 | if (event.key === "Enter") passwordRequest(); 392 | }} 393 | onChange={(e) => { 394 | setResetEmail(e.target.value); 395 | }} 396 | /> 397 | 398 | 401 |
402 | 409 | 410 | 417 |
418 |
419 |
420 |
421 | theme.zIndex.drawer + 1 }} 423 | open={loading} 424 | onClick={handleLoading} 425 | > 426 | 427 | 428 |
429 | ); 430 | }; 431 | 432 | export default Home; 433 | -------------------------------------------------------------------------------- /one-social-media/src/app/components/useDebounceEffect.jsx: -------------------------------------------------------------------------------- 1 | import { useEffect } from "react"; 2 | 3 | export function useDebounceEffect(fn, waitTime, deps) { 4 | useEffect(() => { 5 | const timer = setTimeout(() => { 6 | fn.apply(undefined, deps); 7 | }, waitTime); 8 | return () => { 9 | clearTimeout(timer); 10 | }; 11 | }, deps); 12 | } 13 | -------------------------------------------------------------------------------- /one-social-media/src/app/data/Data.js: -------------------------------------------------------------------------------- 1 | export const footerLinks = [ 2 | { 3 | title: "About", 4 | links: [ 5 | { title: "About Us", url: "https://hareeshdhruva.vercel.app/" }, 6 | ], 7 | }, 8 | { 9 | title: "Socials", 10 | links: [ 11 | { title: "Linkedin", url: "https://www.linkedin.com/in/hareesh-dhruva-797240296" }, 12 | { title: "Git hub", url: "https://github.com/HareeshDhruva" }, 13 | ], 14 | }, 15 | ]; 16 | -------------------------------------------------------------------------------- /one-social-media/src/app/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HareeshDhruva/osm/a227fa46f76bf4cdac4e7f6f622b48c9417c3511/one-social-media/src/app/favicon.ico -------------------------------------------------------------------------------- /one-social-media/src/app/globals.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Poppins&display=swap"); 2 | @tailwind base; 3 | @tailwind components; 4 | @tailwind utilities; 5 | 6 | ::-webkit-scrollbar { 7 | width: 1px; 8 | visibility: hidden; 9 | } 10 | 11 | ::-webkit-scrollbar { 12 | display: block; 13 | } 14 | 15 | ::-webkit-scrollbar-thumb { 16 | border-radius: 20%; 17 | visibility: hidden; 18 | } 19 | 20 | body { 21 | font-size: 16px; 22 | background-color: black; 23 | font-family: "Poppins", sans-serif; 24 | } 25 | 26 | html { 27 | font-family: "Poppins", sans-serif; 28 | } 29 | 30 | @media only screen and (max-width: 600px) { 31 | body { 32 | font-size: 12px; 33 | } 34 | } 35 | 36 | @media only screen and (min-width: 601px) and (max-width: 900px) { 37 | body { 38 | font-size: 14px; 39 | } 40 | } 41 | 42 | @media only screen and (min-width: 901px) { 43 | body { 44 | font-size: 15px; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /one-social-media/src/app/home/page.jsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | import ProfileCard from "../components/homecomponents/Profile/ProfileCard"; 3 | import NavBar from "../components/NavBar"; 4 | import Footer from "../components/Footer"; 5 | import Post from "../components/Post/Post"; 6 | import FriendRequest from "../components/homecomponents/FriendRequest"; 7 | import Suggestion from "../components/homecomponents/Suggestion"; 8 | import Friends from "../components/homecomponents/Friends"; 9 | import { useQuery } from "@tanstack/react-query"; 10 | import { adminData } from "../utils/api"; 11 | import Backdrop from "@mui/material/Backdrop"; 12 | import CircularProgress from "@mui/material/CircularProgress"; 13 | 14 | const Home = () => { 15 | const { 16 | data: Admin, 17 | isLoading: loading, 18 | isSuccess: success, 19 | } = useQuery({ queryKey: ["Admin"], queryFn: adminData }); 20 | return ( 21 |
22 | {Admin && ( 23 | <> 24 | 25 |
26 |
27 |
28 | 29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 | 37 |
38 |
39 |
50 | ); 51 | }; 52 | 53 | export default Home; 54 | -------------------------------------------------------------------------------- /one-social-media/src/app/layout.js: -------------------------------------------------------------------------------- 1 | import "./globals.css"; 2 | import { Inter } from "next/font/google"; 3 | const inter = Inter({ subsets: ["latin"] }); 4 | import PhotoContestProvider from "./Context/UserContest"; 5 | import QueryProvider from "./QueryProvider"; 6 | 7 | export const metadata = { 8 | title: "one social media", 9 | description: 10 | "Connecting people, one post at a time. Welcome to one social media platform for sharing moments, connecting with friends, and discovering what matters to you. Join the community today and make every day memorable. #ConnectShareDiscover #SocialMediaRevolution #oms #one-social-media #oneSocialMedia #onesocialmedia #1socialmedia", 11 | }; 12 | 13 | export default function RootLayout({ children }) { 14 | return ( 15 | 16 | 17 | 18 | {children} 19 | 20 | 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /one-social-media/src/app/page.js: -------------------------------------------------------------------------------- 1 | import Register from "@/app/components/login/Main"; 2 | import Leftpart from "./components/LogoPart"; 3 | 4 | export default function Home() { 5 | return ( 6 | <> 7 |
8 |
9 |
10 | 11 |
12 |
13 | 14 |
15 |
16 |
17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /one-social-media/src/app/utils/api.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | const URL = process.env.NEXT_PUBLIC_BACKEND; 3 | const token = typeof window !== "undefined" ? localStorage.getItem("user") : null; 4 | 5 | export const adminData = async () => { 6 | const res = await axios.post(`${URL}/getuser`, { 7 | headers: { 8 | "Content-Type": "application/json", 9 | authorization: token ? `Bearer ${token}` : "", 10 | }, 11 | }); 12 | return res.data.data; 13 | }; 14 | 15 | export const getUser = async (id) => { 16 | const res = await axios.post(`${URL}/getuser/${id}`, { 17 | headers: { 18 | "Content-Type": "application/json", 19 | authorization: token ? `Bearer ${token}` : "", 20 | }, 21 | }); 22 | if (res.status === 200) { 23 | return res.data.data; 24 | } 25 | }; 26 | 27 | export const suggestionMode = async () => { 28 | const res = await axios.post(`${URL}/suggested`, { 29 | headers: { 30 | "Content-Type": "application/json", 31 | authorization: token ? `Bearer ${token}` : "", 32 | }, 33 | }); 34 | if (res.status === 200) { 35 | return res.data.data; 36 | } 37 | }; 38 | 39 | export const friendRequestMode = async () => { 40 | const res = await axios.post(`${URL}/getFriendRequest`, { 41 | headers: { 42 | "Content-Type": "application/json", 43 | authorization: token ? `Bearer ${token}` : "", 44 | }, 45 | }); 46 | return res.data.data; 47 | }; 48 | 49 | export const friendRequestAcceptMode = async (data) => { 50 | const res = await axios.post(`${URL}/acceptFriendRequest`, { 51 | data: data, 52 | headers: { 53 | "Content-Type": "application/json", 54 | authorization: token ? `Bearer ${token}` : "", 55 | }, 56 | }); 57 | if (res.status === 200) { 58 | return res.data.message; 59 | } 60 | }; 61 | 62 | export const updateProfilePhoto = (data) => { 63 | return async (dispatch) => { 64 | await axios.post(`${URL}/updateProfilePhoto`, { 65 | data: data, 66 | headers: { 67 | "Content-Type": "application/json", 68 | authorization: token ? `Bearer ${token}` : "", 69 | }, 70 | }); 71 | }; 72 | }; 73 | 74 | export const sendFriendRequestMod = async (requestId) => { 75 | const res = await axios.post(`${URL}/sendFriendRequest`, { 76 | data: requestId, 77 | headers: { 78 | "Content-Type": "application/json", 79 | authorization: token ? `Bearer ${token}` : "", 80 | }, 81 | }); 82 | return res.data.message; 83 | }; 84 | 85 | export const getAllPost = async () => { 86 | const res = await axios.get(`${URL}`); 87 | return res.data.data; 88 | }; 89 | 90 | export const likeAPost = (id) => { 91 | return async (dispatch) => { 92 | await axios 93 | .post(`${URL}/like/${id}`, { 94 | headers: { 95 | "Content-Type": "application/json", 96 | authorization: token ? `Bearer ${token}` : "", 97 | }, 98 | }) 99 | .then((response) => { 100 | if (response.status === 200) { 101 | console.log("success"); 102 | } 103 | }) 104 | .catch((error) => { 105 | console.log(error.message); 106 | }); 107 | }; 108 | }; 109 | 110 | export const getComment = async (id) => { 111 | const res = await axios.get(`${URL}/comment/${id}`, { 112 | headers: { 113 | "Content-Type": "application/json", 114 | authorization: token ? `Bearer ${token}` : "", 115 | }, 116 | }); 117 | return res.data.data; 118 | }; 119 | 120 | export const makeAComment = async (data, id) => { 121 | if (data) { 122 | return await axios.post(`${URL}/comment-post/${id}`, { 123 | comment: data, 124 | headers: { 125 | "Content-Type": "application/json", 126 | authorization: token ? `Bearer ${token}` : "", 127 | }, 128 | }); 129 | } 130 | }; 131 | 132 | export const replyCommentMod = async (comment, from, url, id) => { 133 | if (comment) { 134 | const data = { comment, from, url }; 135 | return await axios.post(`${URL}/reply-comment/${id}`, { 136 | data: data, 137 | headers: { 138 | "Content-Type": "application/json", 139 | authorization: token ? `Bearer ${token}` : "", 140 | }, 141 | }); 142 | } 143 | }; 144 | 145 | export const getUserPost = async (id) => { 146 | const res = await axios.post(`${URL}/get-user-post/${id}`, { 147 | headers: { 148 | "Content-Type": "application/json", 149 | authorization: token ? `Bearer ${token}` : "", 150 | }, 151 | }); 152 | if (res.status == 200) { 153 | return res.data.data; 154 | } 155 | }; 156 | 157 | 158 | export const updateUser = async (pagedata) => { 159 | const response = await axios.post(`${URL}/updateUser`, { 160 | data: pagedata, 161 | headers: { 162 | "Content-Type": "application/json", 163 | authorization: token ? `Bearer ${token}` : "", 164 | }, 165 | }); 166 | return response.data.data; 167 | }; 168 | 169 | export const likeAcomment = async (data) => { 170 | const { id, rid } = data; 171 | return await axios.post(`${URL}/like-comment/${id}/${rid}`, { 172 | headers: { 173 | "Content-Type": "application/json", 174 | authorization: token ? `Bearer ${token}` : "", 175 | }, 176 | }); 177 | }; 178 | 179 | export const deletePost = async (id) => { 180 | const res = await axios.post(`${URL}/delete-post/${id}`, { 181 | headers: { 182 | "Content-Type": "application/json", 183 | authorization: token ? `Bearer ${token}` : "", 184 | }, 185 | }); 186 | return res.data.message; 187 | }; 188 | 189 | export const deleteFriend = async (data) => { 190 | const res = await axios.post(`${URL}/deleteFriend`, { 191 | data: data, 192 | headers: { 193 | "Content-Type": "application/json", 194 | authorization: token ? `Bearer ${token}` : "", 195 | }, 196 | }); 197 | return res.data.message; 198 | }; 199 | 200 | export const profileUpdate = async(file)=>{ 201 | console.log(file) 202 | return await axios.post(`${URL}/updateProfilePhoto`, { 203 | method: "POST", 204 | data:file, 205 | headers: { 206 | "Content-Type": "application/json", 207 | authorization: token ? `Bearer ${token}` : "", 208 | }, 209 | }); 210 | } 211 | 212 | export const makeApost = async (description, image) => { 213 | const data = { description, image }; 214 | return await axios.post(`${URL}/create-post`, { 215 | data: data, 216 | headers: { 217 | "Content-Type": "application/json", 218 | authorization: token ? `Bearer ${token}` : "", 219 | }, 220 | }); 221 | }; -------------------------------------------------------------------------------- /one-social-media/tailwind.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('tailwindcss').Config} */ 2 | module.exports = { 3 | content: [ 4 | "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", 5 | "./src/components/**/*.{js,ts,jsx,tsx,mdx}", 6 | "./src/app/**/*.{js,ts,jsx,tsx,mdx}", 7 | ], 8 | theme: { 9 | extend: { 10 | backgroundImage: { 11 | "gradient-radial": "radial-gradient(var(--tw-gradient-stops))", 12 | "gradient-conic": 13 | "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))", 14 | }, 15 | }, 16 | }, 17 | plugins: [], 18 | }; 19 | -------------------------------------------------------------------------------- /server/.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 | *.pem 17 | 18 | # debug 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | 23 | # local env files 24 | .env*.local 25 | .env 26 | 27 | # vercel 28 | .vercel 29 | 30 | # typescript 31 | *.tsbuildinfo 32 | next-env.d.ts 33 | -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const connection = async (URL) => { 4 | try { 5 | const connected = await mongoose.connect(URL); 6 | if (connected) { 7 | console.log("Dastabase connected Sucessfullly"); 8 | } else { 9 | console.log("DB connected fail"); 10 | } 11 | } catch (error) { 12 | console.log(error); 13 | } 14 | }; 15 | module.exports = connection; 16 | -------------------------------------------------------------------------------- /server/controllers/authController.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/userModels"); 2 | const { hasing, createJWT ,comparePassword} = require("../utils"); 3 | const {sendNotififcation} = require('../utils/sendVerification') 4 | const bcrypt = require('bcrypt'); 5 | const { sendPasswordchangeEmail } = require("../utils/passwordChange"); 6 | const {sendPasswordReset} = require('../utils/passwordResetRequest'); 7 | const jwt = require("jsonwebtoken"); 8 | 9 | const register = async(req,res) =>{ 10 | const {firstname,lastname,email,password,DOB,gender} = req.body; 11 | if(!firstname || !lastname || !email || !password){ 12 | return res.status(201).json({message:"Provide all Fields"}); 13 | } 14 | try{ 15 | const ExistUser = await User.findOne({email}); 16 | if(ExistUser){ 17 | return res.status(201).json({message:"Email Already Exist"}); 18 | } 19 | 20 | const hasedPassword = await hasing(password); 21 | const user = await User.create({ 22 | firstname, 23 | lastname, 24 | email:email.toLowerCase(), 25 | DOB, 26 | gender, 27 | password:hasedPassword, 28 | }) 29 | sendNotififcation(user,res) 30 | user.save(); 31 | } 32 | catch(err){ 33 | res.status(201).json({message:err.message}); 34 | } 35 | } 36 | 37 | 38 | const login = async(req,res) => { 39 | const {email,password} = req.body; 40 | try{ 41 | if(!email || !password){ 42 | return res.status(201).json({message:"Enter Email And Password"}) 43 | } 44 | const user = await User.findOne({email}); 45 | if(!user){ 46 | return res.status(201).json({message:"User Not Exist"}) 47 | } 48 | const validPass = bcrypt.compare(password, user.password) 49 | 50 | if(!validPass){ 51 | return res.status(201).json({message:"Incorrect Password"}) 52 | } 53 | if(user.verified === true){ 54 | const token = createJWT(user._id) 55 | res.cookie('token', token, { 56 | path: "/", 57 | maxAge: 90000, 58 | sameSite: 'None', 59 | secure: true, 60 | Domain:"osm-beta.vercel.app" 61 | }); 62 | return res.status(200).json({ data:token}); 63 | } 64 | else{ 65 | res.status(201).json({message:"Please Verify The Email"}); 66 | } 67 | } 68 | catch(error){ 69 | return res.status(201).json({message:error}); 70 | } 71 | } 72 | 73 | const resetPasswordRequest = async(req,res) => { 74 | try{ 75 | const {email} = req.body; 76 | const user = await User.findOne({email}); 77 | if(!user){ 78 | return res.status(201).json({message:"Email Not Found"}) 79 | } 80 | sendPasswordReset(user,res); 81 | } 82 | catch(error){ 83 | res.status(201).json({message:"User Not Found"}) 84 | } 85 | } 86 | 87 | const passwordChange = async (req,res) => { 88 | const token = req.cookies.token; 89 | if(!token){ 90 | return res.status(201).json({message:'User Not Login'}); 91 | } 92 | const payload = jwt.decode(token); 93 | const {password,newPassword} = req.body; 94 | const user = await User.findOne({_id:payload.userId}); 95 | if(!user){ 96 | return res.status(201).json({message:"This Email Not Found"}) 97 | } 98 | const result = await comparePassword(password,user.password); 99 | 100 | if(result){ 101 | const hasedPassword = await hasing(newPassword); 102 | const newuser = await User.findOneAndUpdate({_id:payload.userId},{password:hasedPassword}) 103 | sendPasswordchangeEmail(newuser,res); 104 | console.log("Password Change Sucess"); 105 | } 106 | else{ 107 | res.status(201).json({message:"Incorrect Previos Password"}) 108 | } 109 | } 110 | 111 | const verifiedpasswordChange = async(req,res) => { 112 | try{ 113 | const hasedPassword = await hasing(req.body.newPassword); 114 | const newuser = await User.findOneAndUpdate({_id:req.body.userId},{password:hasedPassword}) 115 | sendPasswordchangeEmail(newuser,res); 116 | } 117 | catch(error){ 118 | res.status(201).json({message:"fail"}); 119 | } 120 | } 121 | 122 | const logout = (req,res)=>{ 123 | const token = ""; 124 | res.status(200).cookie("token",token,{httpOnly:true,expaisIn:"1D", path: "/"}).json({message:"logout"}); 125 | } 126 | 127 | 128 | module.exports = {register,login,logout,resetPasswordRequest,passwordChange,verifiedpasswordChange} 129 | 130 | -------------------------------------------------------------------------------- /server/controllers/comments.js: -------------------------------------------------------------------------------- 1 | const Comment = require("../models/commentModel"); 2 | const Post = require("../models/postModel"); 3 | 4 | const getComments = async (req, res) => { 5 | try { 6 | const { postId } = req.params; 7 | const postComment = await Comment.find({ postId }) 8 | .populate({ 9 | path: "userId postId", 10 | select: "-password", 11 | }) 12 | .populate({ 13 | path: "replies.userId", 14 | select: "-password", 15 | }) 16 | .sort({ _id: -1 }); 17 | res.status(200).json({ 18 | success: true, 19 | message: "success", 20 | data: postComment, 21 | }); 22 | } catch (error) { 23 | res.status(201).json({ message: "fail" }); 24 | } 25 | }; 26 | 27 | const likeApost = async (req, res) => { 28 | try { 29 | const { userId } = req.body.user; 30 | const { id } = req.params; 31 | const post = await Post.findById({ _id: id }); 32 | if (post.likes.includes(String(userId))) { 33 | post.likes = post.likes.filter((pid) => pid !== String(userId)); 34 | } else { 35 | post.likes.push(userId); 36 | } 37 | const newPost = await Post.findByIdAndUpdate(id, post); 38 | 39 | res.status(200).json({ 40 | success: true, 41 | message: "successfully", 42 | data: newPost, 43 | }); 44 | } catch (error) { 45 | res.status(201).json({ message: "something went wrong" }); 46 | } 47 | }; 48 | 49 | const likeAcomment = async (req, res) => { 50 | const { userId } = req.body.user; 51 | const { id, rid } = req.params; 52 | try { 53 | if (rid === undefined || rid === null || rid === "false") { 54 | const comment = await Comment.findById(id); 55 | const index = comment.likes.findIndex((el) => el === String(userId)); 56 | if (index === -1) { 57 | comment.likes.push(userId); 58 | } else { 59 | comment.likes = comment.likes.filter((i) => i === String(userId)); 60 | } 61 | 62 | const updated = await Comment.findByIdAndUpdate(id, comment, { 63 | new: true, 64 | }); 65 | res.status(200).json({ 66 | success: true, 67 | message: "Successfully", 68 | data: updated, 69 | }); 70 | } else { 71 | const replyComment = await Comment.findOne( 72 | { _id: id }, 73 | { 74 | replies: { 75 | $elemMatch: { 76 | _id: rid, 77 | }, 78 | }, 79 | } 80 | ); 81 | const index = replyComment?.replies[0]?.likes.findIndex( 82 | (i) => i === String(userId) 83 | ); 84 | if (index === -1) { 85 | replyComment.replies[0].likes.push(userId); 86 | } else { 87 | replyComment.replies[0].likes = replyComment.replies[0]?.likes.filter( 88 | (i) => i !== String(userId) 89 | ); 90 | } 91 | const query = { _id: id, "replies._id": rid }; 92 | const update = { 93 | $set: { 94 | "replies.$.likes": replyComment.replies[0].likes, 95 | }, 96 | }; 97 | const result = await Comment.findOneAndUpdate(query, update, { 98 | new: true, 99 | }); 100 | res.status(200).json(result); 101 | } 102 | } catch (error) { 103 | res.status(201).json({ message: "something went wrong" }); 104 | } 105 | }; 106 | 107 | const commentPost = async (req, res) => { 108 | try { 109 | const { comment, from } = req.body; 110 | const { userId } = req.body.user; 111 | const { id } = req.params; 112 | if (comment === null) { 113 | res.status(404).json({ message: "comment is required" }); 114 | } 115 | const newComment = new Comment({ comment, from, userId, postId: id }); 116 | await newComment.save(); 117 | const post = await Post.findById(id); 118 | post.comments.push(newComment._id); 119 | const UpdatePost = await Post.findByIdAndUpdate(id, post, { new: true }); 120 | res.status(200).json({ 121 | success: true, 122 | message: "Successfully", 123 | data: UpdatePost, 124 | }); 125 | } catch (error) { 126 | res.status(201).json("something went wrong"); 127 | } 128 | }; 129 | 130 | const replyPostComment = async (req, res, next) => { 131 | const { userId } = req.body.user; 132 | const { comment, from, url } = req.body.data; 133 | const { id } = req.params; 134 | if (comment === null) { 135 | return res.status(201).json({ message: "Comment is Requires" }); 136 | } 137 | try { 138 | const commentInfo = await Comment.findById(id); 139 | commentInfo.replies.push({ 140 | comment, 141 | from, 142 | url, 143 | userId, 144 | created_At: Date.now(), 145 | }); 146 | commentInfo.save(); 147 | res.status(200).json({ data: commentInfo }); 148 | } catch (error) { 149 | res.status(201).json({ message: "somthing went wrong" }); 150 | return; 151 | } 152 | }; 153 | 154 | module.exports = { 155 | getComments, 156 | likeApost, 157 | likeAcomment, 158 | commentPost, 159 | replyPostComment, 160 | }; 161 | -------------------------------------------------------------------------------- /server/controllers/passwordReset.js: -------------------------------------------------------------------------------- 1 | const PasswordReset = require("../models/passwordResetSchema"); 2 | const User = require("../models/userModels"); 3 | const { decodePassword } = require("../utils/index"); 4 | 5 | const passworsReset = async (req, res) => { 6 | const { userId } = req.params; 7 | try { 8 | const result = await PasswordReset.findOne({ userId }); 9 | const { expires_At } = result; 10 | if (result) { 11 | if (expires_At < Date.now()) { 12 | await PasswordReset.findOneAndDelete({ userId }) 13 | .then(() => { 14 | User.findOne({ _id: userId }) 15 | .then(() => { 16 | const message = "Reset token has expaired"; 17 | res.redirect( 18 | `/user/password-reset?status=error&message=${message}` 19 | ); 20 | }) 21 | .catch((error) => { 22 | res.redirect(`/user/password-reset?message=${error}`); 23 | }); 24 | }) 25 | .catch((error) => { 26 | res.redirect(`/user/password-reset?message=${error}`); 27 | }); 28 | } else { 29 | decodePassword(userId, result.token) 30 | .then(async (isMatch) => { 31 | if (isMatch) { 32 | await User.findOne({ _id: userId }) 33 | .then((user) => { 34 | if(user){ 35 | res.redirect(`/user/password-reset?_id=${userId}`); 36 | } 37 | }) 38 | .catch((error) => { 39 | res.redirect(`/user/password-reset?status=fail`); 40 | }); 41 | } else { 42 | res.redirect( 43 | `/user/password-reset?status=succes&message=${isMatch}` 44 | ); 45 | } 46 | }) 47 | .catch((error) => { 48 | res.redirect(`/user/password-reset?message=${error}`); 49 | }); 50 | } 51 | } 52 | } catch (error) { 53 | res.status(201).json({ message: "user not exist" }); 54 | } 55 | }; 56 | 57 | module.exports = passworsReset; 58 | -------------------------------------------------------------------------------- /server/controllers/post.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const Post = require("../models/postModel"); 3 | const cloudinary = require('cloudinary'); 4 | 5 | const createPost = async (req, res) => { 6 | try { 7 | const { userId } = req.body.user; 8 | const { description, image } = req.body.data; 9 | if (!image) { 10 | return res.status(201).json("image must!"); 11 | } 12 | const post = await Post.create({ 13 | userId, 14 | description, 15 | image, 16 | }); 17 | res.status(200).json({ data: post }); 18 | } catch (error) { 19 | res.status(201).json({ message: "failed in post" }); 20 | } 21 | }; 22 | 23 | const getPost = async (req, res) => { 24 | try { 25 | const posts = await Post.find() 26 | .populate({ 27 | path: 'userId', 28 | select: '-password', 29 | }) 30 | .populate({ 31 | path: 'comments', 32 | populate: { 33 | path: 'userId', 34 | select: '-password', 35 | }, 36 | }) 37 | .sort({ _id: -1 }); 38 | res.status(200).json({ 39 | data: posts, 40 | success: true, 41 | message: "successfuuly", 42 | }); 43 | } catch (error) { 44 | res.status(201).json({ message: "something went wrong" }); 45 | } 46 | }; 47 | 48 | const getuserPost = async (req, res) => { 49 | try { 50 | const { id } = req.params; 51 | const userpost = await Post.find({ userId: id }) 52 | .populate({ 53 | path: "userId", 54 | select: "-password", 55 | }) 56 | .sort({ _id: -1 }); 57 | 58 | res.status(200).json({ 59 | message: "successfully", 60 | success: true, 61 | data: userpost, 62 | }); 63 | } catch (error) { 64 | res.status(201).json({ message: "Post not yet !" }); 65 | } 66 | }; 67 | 68 | const deletePost = async (req, res) => { 69 | const { id } = req.params; 70 | const { userId } = req.body.user; 71 | 72 | try { 73 | const postfound = await Post.findById({ _id: id }); 74 | if (postfound) { 75 | if (postfound.userId.toString() === userId) { 76 | const result = await Post.findByIdAndDelete({ _id: id }); 77 | if (result) { 78 | cloudinary.v2.api.delete_resources(postfound.image.public_id).then(()=>{ 79 | return res.status(200).json({ message: "Delete Success"}); 80 | }); 81 | } 82 | } else { 83 | res.status(201).json({ message: `Only admin can delete` }); 84 | } 85 | } else { 86 | res.status(201).json({ message: "Post already deleted" }); 87 | } 88 | } catch (error) { 89 | res.status(201).json({ message: "Somthing went wrong" }); 90 | } 91 | }; 92 | 93 | module.exports = { createPost, getuserPost, deletePost, getPost }; 94 | -------------------------------------------------------------------------------- /server/controllers/userControl.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Verification = require("../models/emailVerificatin"); 3 | const User = require("../models/userModels"); 4 | const { decodePassword } = require("../utils/index"); 5 | 6 | const verfiyEmail = async (req, res) => { 7 | const { userId } = req.params; 8 | try { 9 | const result = await Verification.findOne({ userId }); 10 | const { expires_At } = result; 11 | if (result) { 12 | if (expires_At < Date.now()) { 13 | await Verification.findOne({ userId }) 14 | .then(() => { 15 | User.findOne({ _id: userId }) 16 | .then(() => { 17 | const message = "Verification token has expaired"; 18 | res.redirect(`/user/verified?status=error&message=${message}`); 19 | }) 20 | .catch((error) => { 21 | res.redirect(`/user/verified?message=${error}`); 22 | }); 23 | }) 24 | .catch((error) => { 25 | res.redirect(`/user/verified?message=${error}`); 26 | }); 27 | } else { 28 | decodePassword(userId, result.token) 29 | .then(async (isMatch) => { 30 | if (isMatch) { 31 | await User.findOneAndUpdate({ _id: userId }, { verified: true }) 32 | .then((user) => { 33 | if(user){ 34 | res.redirect(`/user/verified?status=success`); 35 | } 36 | }) 37 | .catch((error) => { 38 | res.redirect(`/user/verified?status=fail`); 39 | }); 40 | } else { 41 | res.redirect(`/user/verified?status=succes&message=${isMatch}`); 42 | } 43 | }) 44 | .catch((error) => { 45 | res.redirect(`/user/verified?message=${error}`); 46 | }); 47 | } 48 | } 49 | } catch (error) { 50 | res.status(201).json({ message: "user not exist" }); 51 | } 52 | }; 53 | 54 | module.exports = verfiyEmail; 55 | -------------------------------------------------------------------------------- /server/controllers/users.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const User = require("../models/userModels"); 3 | const FriendRequest = require("../models/requestSchema"); 4 | const cloudinary = require('cloudinary'); 5 | 6 | const getUser = async (req, res) => { 7 | const { userId } = req.body.user; 8 | const { id } = req.params; 9 | const user = await User.findById(id ?? userId).populate({ 10 | path: "friends", 11 | select: "-password", 12 | }); 13 | 14 | if (user) { 15 | res.status(200).json({ data: user }); 16 | } else { 17 | res.status(201).json({ message: "users not found" }); 18 | } 19 | }; 20 | 21 | const updateUser = async (req, res) => { 22 | const { userId } = req.body.user; 23 | const { data } = req.body; 24 | 25 | const filteredUser = Object.fromEntries( 26 | Object.entries(data).filter(([_, value]) => value !== "") 27 | ); 28 | const updatedUser = await User.findByIdAndUpdate( 29 | { _id: userId }, 30 | filteredUser 31 | ); 32 | 33 | if (updatedUser) { 34 | res.status(200).json({ data: updatedUser }); 35 | } else { 36 | res.status(201).json({ message: "users update fail" }); 37 | } 38 | }; 39 | 40 | const updateProfilePhoto = async (req, res) => { 41 | try { 42 | const { userId } = req.body.user; 43 | const { data } = req.body; 44 | if (!data) { 45 | return res.status(400).json({ message: "Provide all Fields" }); 46 | } 47 | const user = await User.findOne({ _id: userId }); 48 | if (!user) { 49 | return res.status(404).json({ message: "User not found" }); 50 | } 51 | const deleteCloudinary = cloudinary.v2.api.delete_resources(user.profileUrl.public_id); 52 | user.profileUrl = data; 53 | const saveUser = user.save(); 54 | await Promise.all([deleteCloudinary, saveUser]); 55 | res.status(200).json({ data: user }); 56 | } catch (error) { 57 | console.error(error); 58 | res.status(500).json({ message: "Internal Server Error" }); 59 | } 60 | }; 61 | 62 | const sendfriendRequest = async (req, res, next) => { 63 | try { 64 | const { userId } = req.body.user; 65 | const { requestId } = req.body.data; 66 | 67 | const existRequest = await FriendRequest.findOne({ 68 | requestFrom: userId, 69 | requestTo: requestId, 70 | }); 71 | 72 | if (existRequest) { 73 | return res.status(201).json({ message: "You Have Alredy Sent Request" ,data:existRequest.status}); 74 | } 75 | 76 | const accountExist = await FriendRequest.findOne({ 77 | requestFrom: requestId, 78 | requestTo: userId, 79 | }); 80 | 81 | if (accountExist) { 82 | return res.status(201).json({ message: "You Have Alredy Received Request",data:accountExist.status }); 83 | } 84 | 85 | const newRequest = await FriendRequest.create({ 86 | requestFrom: userId, 87 | requestTo: requestId, 88 | }); 89 | newRequest.save(); 90 | return res.status(200).json({ success: true, message: "Sent Request" }); 91 | } catch (error) { 92 | return res.status(201).json({ success: true, message: "Sent Request Fail" }); 93 | } 94 | }; 95 | 96 | const getfriendRequest = async (req, res) => { 97 | const { userId } = req.body.user; 98 | try { 99 | const request = await FriendRequest.find({ 100 | requestTo: userId, 101 | requestStatus: "Pending", 102 | }) 103 | .populate({ 104 | path: "requestFrom", 105 | select: "-password", 106 | }) 107 | .limit(10) 108 | .sort({ _id: -1 }); 109 | res.status(200).json({ success: true, data: request }); 110 | } catch (error) { 111 | res.status(201).json({ message: "Not Exist" }); 112 | } 113 | }; 114 | 115 | const acceptfriendRequest = async (req, res) => { 116 | const id = req.body.user.userId; 117 | const { rid, requestStatus } = req.body.data; 118 | const status = requestStatus; 119 | const exist = await FriendRequest.findById(rid); 120 | if (!exist) { 121 | return res.status(201).json({ message: "No Friend requset found" }); 122 | } 123 | try { 124 | const newExist = await FriendRequest.findByIdAndUpdate( 125 | { _id: rid, requestStatus: status }, 126 | { requestStatus: "Accepted" }, 127 | { new: true } 128 | ); 129 | 130 | if (newExist && newExist.requestStatus === "Accepted") { 131 | const admin = await User.findById(id); 132 | const friendId = newExist.requestFrom; 133 | 134 | if (!admin.friends.includes(friendId)) { 135 | admin.friends.push(friendId); 136 | await admin.save(); 137 | } 138 | 139 | const friend = await User.findById(friendId); 140 | if (!friend.friends.includes(id)) { 141 | friend.friends.push(id); 142 | await friend.save(); 143 | } 144 | } 145 | 146 | res.status(200).json({ 147 | success: true, 148 | message: "Friend Request Accepted", 149 | }); 150 | } catch (error) { 151 | console.error(error); 152 | res.status(201).json({ 153 | success: false, 154 | message: "An error occurred", 155 | }); 156 | } 157 | }; 158 | 159 | const profileView = async (req, res) => { 160 | const { userId } = req.body.user; 161 | const { id } = req.body; 162 | try { 163 | const user = await User.findById(id); 164 | user.views.push(userId); 165 | await user.save(); 166 | res.status(200).json({ 167 | success: true, 168 | message: "successfully viewd", 169 | }); 170 | } catch (error) { 171 | res.status(201).json({ success: false, message: "failed" }); 172 | } 173 | }; 174 | 175 | const suggested = async (req, res) => { 176 | const { userId } = req.body.user; 177 | try { 178 | let queryObject = {}; 179 | queryObject._id = { $ne: userId }; 180 | queryObject.friends = { $nin: userId }; 181 | queryObject.verified = true; 182 | let QueryResult = await User.find(queryObject) 183 | .limit(15) 184 | .select("-password"); 185 | const suggestedFriends = QueryResult; 186 | res.status(200).json({ data: suggestedFriends, success: true }); 187 | } catch (error) { 188 | res.status(201).json({ success: false, message: "failed" }); 189 | } 190 | }; 191 | 192 | const searchUser = async (req, res) => { 193 | try { 194 | const { search } = req.body; 195 | const posts = await User.find({ 196 | firstname: { $regex: search, $options: "i" }, 197 | }); 198 | res.status(200).json({ 199 | data: posts, 200 | success: true, 201 | message: "successfully", 202 | }); 203 | } catch (error) { 204 | res.status(201).json({ message: "fail in get post" }); 205 | } 206 | }; 207 | 208 | const removeFriend = async (req, res) => { 209 | try { 210 | const userId = req.body.user.userId; 211 | const friendIdToRemove = req.body.data; 212 | await FriendRequest.findOneAndDelete({requestTo:friendIdToRemove,requestFrom:userId}); 213 | await FriendRequest.findOneAndDelete({requestTo:userId,requestFrom:friendIdToRemove}); 214 | const currentUser = await User.findById(userId); 215 | const friendIndex = currentUser.friends.indexOf(friendIdToRemove); 216 | if (friendIndex !== -1) { 217 | currentUser.friends.splice(friendIndex, 1); 218 | await currentUser.save(); 219 | const friendUser = await User.findById(friendIdToRemove); 220 | const currentUserIndexInFriend = friendUser.friends.indexOf(userId); 221 | if (currentUserIndexInFriend !== -1) { 222 | friendUser.friends.splice(currentUserIndexInFriend, 1); 223 | await friendUser.save(); 224 | return res.status(200).json({ message: `${friendUser.firstname} removed` }); 225 | } else { 226 | return res.status(404).json({ message: "User not found in friend's friend list" }); 227 | } 228 | } else { 229 | return res.status(404).json({ message: "Friend not found in user's friend list" }); 230 | } 231 | } catch (error) { 232 | console.error(error); 233 | return res.status(500).json({ message: "Internal server error" }); 234 | } 235 | }; 236 | 237 | 238 | module.exports = { 239 | getUser, 240 | sendfriendRequest, 241 | getfriendRequest, 242 | acceptfriendRequest, 243 | profileView, 244 | suggested, 245 | updateUser, 246 | updateProfilePhoto, 247 | searchUser, 248 | removeFriend, 249 | }; 250 | -------------------------------------------------------------------------------- /server/middleware.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const userAuth = async (req, res, next) => { 3 | const authHead = req.body?.headers?.authorization; 4 | if (!authHead || !authHead?.startsWith("Bearer")) { 5 | next("Authentication === failed"); 6 | } 7 | const token = authHead?.split(" ")[1]; 8 | try { 9 | const payload = jwt.verify(token, process.env.JWT_SECRET_KEY); 10 | req.body.user = { userId: payload.userId }; 11 | next(); 12 | } catch (error) { 13 | next("authontication fail"); 14 | } 15 | }; 16 | module.exports = userAuth; 17 | -------------------------------------------------------------------------------- /server/models/commentModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const commentSchema = new mongoose.Schema( 4 | { 5 | userId: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 6 | postId: { type: mongoose.Schema.Types.ObjectId, ref: "post" }, 7 | comment: { type: String, require: true }, 8 | from: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 9 | replies: [ 10 | { 11 | rId: { type: mongoose.Schema.Types.ObjectId }, 12 | userId: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 13 | from: { type: String }, 14 | url: { type: String }, 15 | replyAt: { type: String }, 16 | comment: [String], 17 | created_At: { type: Date, default: Date.now() }, 18 | replyed_At: { type: Date, default: Date.now() }, 19 | likes: [String], 20 | }, 21 | ], 22 | likes: [{ type: String }], 23 | }, 24 | { timestamps: true } 25 | ); 26 | 27 | const Comment = mongoose.model("comment", commentSchema); 28 | module.exports = Comment; 29 | -------------------------------------------------------------------------------- /server/models/emailVerificatin.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const emailVerificationSchema = new mongoose.Schema( 4 | { 5 | userId: String, 6 | token: String, 7 | created_At: Date, 8 | expires_At: Date, 9 | }, 10 | { timestamps: true } 11 | ); 12 | 13 | const Verification = mongoose.model( 14 | "emailVarification", 15 | emailVerificationSchema 16 | ); 17 | 18 | module.exports = Verification; 19 | -------------------------------------------------------------------------------- /server/models/passwordResetSchema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const passwordResetSchema = new mongoose.Schema({ 4 | userId: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 5 | email: { type: String, unique: true }, 6 | token: { type: String }, 7 | created_At: Date, 8 | expires_At: Date, 9 | }); 10 | 11 | const PasswordReset = mongoose.model("passwordReset", passwordResetSchema); 12 | 13 | module.exports = PasswordReset; 14 | -------------------------------------------------------------------------------- /server/models/postModel.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const posrSchema = new mongoose.Schema( 4 | { 5 | userId: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 6 | description: { type: String }, 7 | image: { type: Object }, 8 | likes: [String], 9 | comments: [{ type: mongoose.Schema.Types.ObjectId, ref: "comment" }], 10 | }, 11 | { timestamps: true } 12 | ); 13 | 14 | const Post = mongoose.model("post", posrSchema); 15 | module.exports = Post; 16 | -------------------------------------------------------------------------------- /server/models/requestSchema.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const requestSchema = new mongoose.Schema( 4 | { 5 | requestTo: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 6 | requestFrom: { type: mongoose.Schema.Types.ObjectId, ref: "user" }, 7 | requestStatus: { type: String, default: "Pending" }, 8 | }, 9 | { timestamps: true } 10 | ); 11 | 12 | const FriendRequest = mongoose.model("friendRequest", requestSchema); 13 | module.exports = FriendRequest; 14 | -------------------------------------------------------------------------------- /server/models/userModels.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const userSchema = new mongoose.Schema( 4 | { 5 | firstname: { 6 | type: String, 7 | require: true, 8 | }, 9 | lastname: { 10 | type: String, 11 | require: true, 12 | }, 13 | email: { 14 | type: String, 15 | require: true, 16 | unique: true, 17 | }, 18 | password: { 19 | type: String, 20 | require: true, 21 | min: 6, 22 | }, 23 | gender: { 24 | type: String, 25 | }, 26 | DOB: { 27 | type: Date, 28 | }, 29 | location: { 30 | default: null, 31 | type: String, 32 | }, 33 | profileUrl: { 34 | default: null, 35 | type: Object, 36 | }, 37 | profession: { 38 | default: null, 39 | type: String, 40 | }, 41 | views: [String], 42 | verified: { type: Boolean, default: false }, 43 | friends: [{ type: mongoose.Schema.Types.ObjectId, ref: "user" }], 44 | }, 45 | { 46 | timestamps: true, 47 | } 48 | ); 49 | 50 | const User = mongoose.model("user", userSchema); 51 | module.exports = User; 52 | -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "server.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon server.js" 9 | }, 10 | "author": "\"hareesh dhruva\"", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^5.1.1", 14 | "body-parser": "^1.20.2", 15 | "cloudinary": "^2.0.0", 16 | "cookie-parser": "^1.4.6", 17 | "cors": "^2.8.5", 18 | "dotenv": "^16.3.1", 19 | "express": "^4.18.2", 20 | "ioredis": "^5.3.2", 21 | "jsonwebtoken": "^9.0.2", 22 | "mongoose": "^8.1.1", 23 | "mongoose-findorcreate": "^4.0.0", 24 | "morgan": "^1.10.0", 25 | "nodemailer": "^6.9.5", 26 | "nodemon": "^3.0.1", 27 | "otp-generator": "^4.0.1", 28 | "redis": "^4.6.11", 29 | "socket.io": "^4.7.4", 30 | "uuid": "^9.0.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /server/routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const verfiyEmail = require("../controllers/userControl.js"); 3 | const passworsReset = require("../controllers/passwordReset.js"); 4 | 5 | const router = express.Router(); 6 | router.get("/user/verify/:userId/:token", verfiyEmail); 7 | router.get("/user/password-reset/:userId/:token", passworsReset); 8 | module.exports = router; 9 | -------------------------------------------------------------------------------- /server/server.js: -------------------------------------------------------------------------------- 1 | const dotenv = require("dotenv"); 2 | const express = require("express"); 3 | const bodyparser = require("body-parser"); 4 | const cors = require("cors"); 5 | const connection = require("./config"); 6 | 7 | const { 8 | login, 9 | register, 10 | resetPasswordRequest, 11 | passwordChange, 12 | verifiedpasswordChange, 13 | logout, 14 | } = require("./controllers/authController"); 15 | const router = require("./routes/auth"); 16 | const path = require("path"); 17 | const { 18 | getUser, 19 | sendfriendRequest, 20 | getfriendRequest, 21 | acceptfriendRequest, 22 | profileView, 23 | suggested, 24 | updateUser, 25 | updateProfilePhoto, 26 | searchUser, 27 | removeFriend, 28 | } = require("./controllers/users"); 29 | const userAuth = require("./middleware"); 30 | const { 31 | getPost, 32 | createPost, 33 | getuserPost, 34 | deletePost, 35 | } = require("./controllers/post"); 36 | const { 37 | getComments, 38 | likeApost, 39 | likeAcomment, 40 | commentPost, 41 | replyPostComment, 42 | } = require("./controllers/comments"); 43 | 44 | dotenv.config(); 45 | const URL = process.env.MONGO_URL; 46 | const app = express(); 47 | connection(URL); 48 | 49 | app.use(router); 50 | app.use(bodyparser.json({ extended: true })); 51 | app.use(bodyparser.urlencoded({ extended: true })); 52 | 53 | app.use( 54 | cors({ 55 | origin: process.env.FRONTEND, 56 | credentials: true, 57 | }) 58 | ); 59 | 60 | app.post("/register", register); 61 | app.post("/login", login); 62 | 63 | app.get("/user/verify", router); 64 | app.get("/user/verified", (req, res) => { 65 | res.sendFile(path.join(__dirname, "./views/index.html")); 66 | }); 67 | 68 | app.post("/user/password-reset-request", resetPasswordRequest); 69 | app.get("/user/password-reset", (req, res) => { 70 | res.sendFile(path.join(__dirname, "./views/passwordReset.html")); 71 | }); 72 | 73 | app.post("/user/verified-password-change", verifiedpasswordChange); 74 | app.post("/user/password-change", passwordChange); 75 | 76 | app.post("/updateUser", userAuth, updateUser); 77 | app.post("/updateProfilePhoto", userAuth, updateProfilePhoto); 78 | app.post("/getuser/:id?", userAuth, getUser); 79 | app.post("/sendFriendRequest", userAuth, sendfriendRequest); 80 | app.post("/getFriendRequest", userAuth, getfriendRequest); 81 | app.post("/acceptFriendRequest", userAuth, acceptfriendRequest); 82 | app.post("/profileView", userAuth, profileView); //not 83 | app.post("/suggested", userAuth, suggested); 84 | app.post("/searchUser", searchUser); 85 | app.post("/deleteFriend", userAuth, removeFriend); 86 | 87 | app.get("/", getPost); 88 | app.post("/create-post", userAuth, createPost); 89 | app.post("/get-user-post/:id", userAuth, getuserPost); 90 | app.post("/delete-post/:id", userAuth, deletePost); 91 | 92 | app.get("/comment/:postId", getComments); 93 | app.post("/like/:id", userAuth, likeApost); 94 | app.post("/like-comment/:id/:rid?", userAuth, likeAcomment); 95 | app.post("/comment-post/:id", userAuth, commentPost); 96 | app.post("/reply-comment/:id", userAuth, replyPostComment); 97 | 98 | app.post("/logout", logout); //not 99 | app.listen(process.env.PORT, () => { 100 | console.log(`main server started`); 101 | }); 102 | -------------------------------------------------------------------------------- /server/utils/index.js: -------------------------------------------------------------------------------- 1 | const bcrypt = require('bcrypt') 2 | const jwt = require('jsonwebtoken'); 3 | 4 | const hasing = async(userValue) =>{ 5 | const salt = await bcrypt.genSalt(10); 6 | const hasedPassword = await bcrypt.hash(userValue,salt) 7 | return hasedPassword; 8 | } 9 | 10 | function createJWT(id){ 11 | const token = jwt.sign({userId:id},process.env.JWT_SECRET_KEY,{expiresIn:"1d"}); 12 | return token; 13 | } 14 | 15 | async function decodePassword(userId,hasedToken){ 16 | const payload = jwt.decode(hasedToken) 17 | if(payload.userId === userId){ 18 | return true; 19 | } 20 | if(err){ 21 | return false; 22 | } 23 | } 24 | 25 | async function comparePassword(password,hasedPassword){ 26 | const validPass = await bcrypt.compare(password,hasedPassword); 27 | if(validPass){ 28 | return true; 29 | } 30 | else{ 31 | return false; 32 | } 33 | } 34 | 35 | module.exports = {hasing,createJWT,decodePassword,comparePassword}; -------------------------------------------------------------------------------- /server/utils/passwordChange.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | const transporter = nodemailer.createTransport({ 3 | service: "gmail", 4 | port: 587, 5 | auth: { 6 | user: "hareeshdhruva143@gmail.com", 7 | pass: "qxvw xxnp jucp wvre", 8 | }, 9 | }); 10 | 11 | const sendPasswordchangeEmail = async (user, res) => { 12 | const { email, firstname, lastname } = user; 13 | if (!email || !firstname || !lastname) { 14 | return res.status(404).json({ message: "user not found to send message" }); 15 | } 16 | try { 17 | await transporter.sendMail({ 18 | from: '"OSM 👻" ', 19 | to: email, 20 | subject: "Password Change", 21 | text: "Hello", 22 | html: ` 23 | 24 | 25 | 26 | 27 | 28 | Password change 29 | 59 | 60 | 61 |
62 |

Hello ${firstname + " " + lastname}

63 |
64 |
65 |

Your request to change the Password has been Successfully completed!

66 |
67 | 68 | 69 | `, 70 | }); 71 | 72 | res.status(200).json({ message: "Password Change Sucessfully" }); 73 | } catch (error) { 74 | console.log(error); 75 | res.status(201).json({ message: "Something Went Wrong" }); 76 | } 77 | }; 78 | module.exports = { sendPasswordchangeEmail }; 79 | -------------------------------------------------------------------------------- /server/utils/passwordResetRequest.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | const passwordReset = require("../models/passwordResetSchema"); 3 | const { createJWT } = require("./index"); 4 | const { v4: uuidv4 } = require("uuid"); 5 | const { use } = require("bcrypt/promises"); 6 | 7 | const transporter = nodemailer.createTransport({ 8 | service: "gmail", 9 | port: 587, 10 | auth: { 11 | user: "hareeshdhruva143@gmail.com", 12 | pass: "qxvw xxnp jucp wvre", 13 | }, 14 | }); 15 | 16 | const sendPasswordReset = async (user, res) => { 17 | const { _id, email, firstname, lastname } = user; 18 | const token = _id + uuidv4(); 19 | const link = 20 | process.env.APP_URL + "/user/password-reset/" + _id + "/" + token; 21 | try { 22 | const info = await transporter.sendMail({ 23 | from: '"OSM 👻" ', 24 | to: email, 25 | subject: "Password Reset", 26 | text: "Hello", 27 | html: ` 28 | 29 | 30 | 31 | 32 | 33 | Password request 34 | 84 | 85 | 86 |
87 |

${firstname + " " + lastname}

88 |

Thank you for Password Reset service! Please click the button below to reset your password:

89 | Reset Password 90 |
91 | 92 | 93 | `, 94 | }); 95 | try { 96 | const jwtToken = createJWT(_id); 97 | const user = await passwordReset.findOneAndUpdate( 98 | { userId: _id }, 99 | { 100 | userId: _id, 101 | token: jwtToken, 102 | email, 103 | created_At: Date.now(), 104 | expires_At: Date.now() + 3600000, 105 | } 106 | ); 107 | if (user) { 108 | return res 109 | .status(200) 110 | .json({ message: "Check Your Mail Already Sent" }); 111 | } 112 | 113 | const newRequestReset = await passwordReset.create({ 114 | userId: _id, 115 | token: jwtToken, 116 | email, 117 | created_At: Date.now(), 118 | expires_At: Date.now() + 3600000, 119 | }); 120 | 121 | if (!newRequestReset) { 122 | transporter.sendMail(info).then(() => { 123 | res.status(200).json({ message: "Check Your Mail Already Sent" ,data:link}); 124 | }); 125 | } 126 | } catch (error) { 127 | console.log(error); 128 | } 129 | res.status(200).json({ message: "Sucessfully Send Reset Mail",data:link}); 130 | } catch (error) { 131 | console.log(error); 132 | } 133 | }; 134 | module.exports = { sendPasswordReset }; 135 | -------------------------------------------------------------------------------- /server/utils/sendVerification.js: -------------------------------------------------------------------------------- 1 | const nodemailer = require("nodemailer"); 2 | const verification = require("../models/emailVerificatin"); 3 | const { createJWT } = require("."); 4 | const { v4: uuidv4 } = require("uuid"); 5 | 6 | const transporter = nodemailer.createTransport({ 7 | service: "gmail", 8 | port: 587, 9 | auth: { 10 | user: "hareeshdhruva143@gmail.com", 11 | pass: "qxvw xxnp jucp wvre", 12 | }, 13 | }); 14 | 15 | const sendNotififcation = async (user, res) => { 16 | const { _id, email, firstname, lastname } = user; 17 | const token = _id + uuidv4(); 18 | const link = process.env.APP_URL + "/user/verify/" + _id + "/" + token; 19 | try { 20 | const info = await transporter.sendMail({ 21 | from: '"OSM 👻" ', 22 | to: email, 23 | subject: "Email verification", 24 | text: "Hello", 25 | html: ` 26 | 27 | 28 | 29 | 30 | 31 | Email Confirmation 32 | 81 | 82 | 83 |
84 |

${firstname + " " + lastname}

85 |

Thank you for signing up! Please click the button below to confirm your email address:

86 | Confirm Email 87 |
88 | 89 | 90 | `, 91 | }); 92 | try { 93 | const jwtToken = createJWT(_id); 94 | const newVerifiedEmail = await verification.create({ 95 | userId: _id, 96 | token: jwtToken, 97 | created_At: Date.now(), 98 | expires_At: Date.now() + 3600000, 99 | }); 100 | if (!newVerifiedEmail) { 101 | transporter.sendMail(info).then(() => { 102 | res.status(201).send({ 103 | success: "Pending", 104 | message: 105 | "Verification email has been sent to your email for verification", 106 | }); 107 | }); 108 | } 109 | } catch (error) { 110 | console.log(error); 111 | } 112 | res.status(200).json({ data: link, message: "Verify Email Address" }); 113 | } catch (error) { 114 | console.log(error); 115 | } 116 | }; 117 | module.exports = { sendNotififcation }; 118 | -------------------------------------------------------------------------------- /server/vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "server.js", 6 | "use": "@vercel/node" 7 | } 8 | ], 9 | "routes": [ 10 | { "src": "/(.*)", "dest": "server.js" } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /server/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | confirmation 11 | 64 | 65 | 66 |
67 |

Email Confirmation Success

68 |

69 | Thank you for signing up! Please click the button below to confirm your 70 | email address: 71 |

72 | Login 75 |
76 | 77 |
78 |

Email Confirmation Fail

79 |

somethis went wrong! Request foe new Confirmation mail address

80 | Re-try 83 |
84 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /server/views/passwordReset.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | Password Reset 11 | 94 | 95 | 96 |
97 |

Password Reset

98 |
99 | 106 | 113 | 114 |
115 |
116 |
117 |
118 |

Reset Success

119 |
120 |

Thank you

121 | close 124 |
125 |
126 | 183 | 184 | 185 | --------------------------------------------------------------------------------