0% found this document useful (0 votes)
31 views79 pages

WISE

Uploaded by

nitishsahu0507
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
31 views79 pages

WISE

Uploaded by

nitishsahu0507
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 79

PROJECT REPORT

ON
WISE: SOCIAL MEDIA WEB APP
(FOR THE COURSE OF T. Y. B.Sc. COMPUTER SCIENCE)

DESIGNED AND DEVELOPED


BY
ATHARVA GHOLAP

GUIDED BY
MS. PRATIKSHA HARWALKAR

DEPARTMENT OF COMPUTER SCIENCE

PARLE TILAK VIDYALAYA ASSOCIATION’S


MULUND COLLEGE OF COMMERCE (AUTONOMOUS)
(Affiliated to University of Mumbai)
2023-24

MULUND (WEST), MUMBAI-400080


MAHARASHTRA, INDIA
ACKNOWLEDGEMENT

I have a great pleasure in representing this project report entitled


“Wise: Social Media Web App” and I grab this opportunity to convey
my immense regards towards all the distinguished people who have
their valuable contribution in the hour of need.
I like to extend my gratitude to our beloved Principal Dr. Sonali
Pednekar for her timely and prestigious guidance.
I take this opportunity to thank Dr. Reena Nagda, Coordinator of
the Department and all the faculty members of the Department of
Computer Science of Mulund College of Commerce, for giving me an
opportunity to complete this project and the most needed guidance
throughout the duration of the programme.
I am extremely grateful to my project guide Ms. Pratiksha
Harwalkar for her valuable guidance and necessary support during
each phase of the project. She was the source of continuous
encouragement as each milestone was crossed.
Finally, I also owe to my fellow friends who have been a
constant source of help to solve the problems that cropped up during
the project development process.

Atharva Gholap
Contents
1. Title ..................................................................................................................................... 1
2. Introduction ........................................................................................................................ 2
2.1 Objective of the project: .............................................................................................. 2
2.2 Description of the current system: .............................................................................. 2
2.3 Limitation of the current system: ................................................................................ 2
2.4 Description of the proposed system: ........................................................................... 2
2.5 Advantages of the proposed system: ........................................................................... 2
3. Requirement Specification ................................................................................................. 4
3.1 Software Requirements: .............................................................................................. 4
3.2 Hardware Requirements: ............................................................................................. 4
3.3 Data Requirements: ..................................................................................................... 4
3.4 Fact Finding Questions: .............................................................................................. 4
4. System Design Details ........................................................................................................ 5
4.1 Event Table: ................................................................................................................. 5
4.2 Class Diagram ............................................................................................................. 6
4.3 Use Case Diagram ....................................................................................................... 7
4.4 Sequence Diagram....................................................................................................... 8
4.5 Activity Diagram ......................................................................................................... 9
4.6 State Diagram ............................................................................................................ 10
4.7 Package Diagram....................................................................................................... 10
4.8 Component Diagram ................................................................................................. 11
4.9 Development Diagram .............................................................................................. 11
4.10 Database Design (MongoDB) ................................................................................... 12
4.10.1 Database: test ..................................................................................................... 12
4.10.2 Collection: posts................................................................................................. 12
4.10.3 Collection: users................................................................................................. 13
5. System Implementation .................................................................................................... 14
6. Results .............................................................................................................................. 68
6.1 Validation and Naming Conventions......................................................................... 68
6.2 Screenshots ................................................................................................................ 68
6.2.1 Login Page ......................................................................................................... 68
6.2.2 Account Registration Page ................................................................................. 69
6.2.3 Home Page ......................................................................................................... 70
6.2.4 Profile Page ........................................................................................................ 70
6.2.5 NightMode Activated ......................................................................................... 71
6.2.6 Post..................................................................................................................... 71
6.2.7 Logout ................................................................................................................ 72
7. Future Enhancement & Conclusion .................................................................................. 73
7.1 Future Enhancement .................................................................................................. 73
7.2 Conclusions ............................................................................................................... 73
8. References ........................................................................................................................ 73
9. Annexures ............................................................................................................................ 74
9.1 Figures List ................................................................................................................ 74
9.2 Table List ................................................................................................................... 74
Social Media Web Application

1. Title

Topic: Social Media Web Application

Type of Project: Web Application

Developer: Atharva Gholap

Mulund College of Commerce (Autonomous) 2023-24 1


Social Media Web Application

2. Introduction

2.1 Objective of the project:


• Wise is an online and real time platform for the people all around the world
to use it to connect to other people all over the globe.
• It facilitates users to share numerous contents on their profile, interact with
other user and most importantly increase networking and socializing on a
single platform.

2.2 Description of the current system:


• There are many social media webapps available today. Each of these
platforms has its own unique features and target audience.
• This system allow user to share content without any limitation on storage
but are complicated to use and understand.

2.3 Limitation of the current system:


• Lack of emotional and professional connection between people.
• Spreading of fake news and unauthorized information.
• Safety and identity crisis can cause cybercrime.
• A lot of social media platforms are mobile application biased and their
webapp versions are confusing and unresponsive.

2.4 Description of the proposed system:


• This Social media webapp is another mimic of existing social media
platform which allows user to register and login using their email id.
• It will allow the authorized users to follow other users, post multiple media
content and documents, like posts of other and etc.
• It will also have a section for promotion purposes of sponsors.

2.5 Advantages of the proposed system:


• This system will be quick with its response and interaction with other users
• It will have a simple interaction user interface which will be easy for any
users to use and explore.
• This system excludes unnecessary features and focus more on the simplicity.
• It includes features to acknowledge the user of number of people visited
their profile and impression on their posts.
• It is fully responsive and will automatically adjust the arrange of features on
the screen.

Mulund College of Commerce (Autonomous) 2023-24 2


Social Media Web Application

• It will also allow users to post any type of data from photos to any type of
attachments.

Mulund College of Commerce (Autonomous) 2023-24 3


Social Media Web Application

3. Requirement Specification

3.1 Software Requirements:


• Operating System of un-outdated version
Any modern type of browser which supports JavaScript
• Chrome,
• Firefox
• Edge
• Brave

3.2 Hardware Requirements:


• A computer with 4GB of RAM
• Processor- 2GHz
• A stable internet connection
• Disk Space – 1GB or more
• Sustainable Keyboard & Mouse

3.3 Data Requirements:


• First Name
• Last Name
• Email
• Password
• Pictures
• Videos
• Audios
• Location
• Occupation
• User Id
• Description

3.4 Fact Finding Questions:


• How can it be different from other social media webapps?
• What is the scope of this proposed idea?
• In which way it can contribute to society?
• How can you grow this social media platform?
• Is the data shared across the webapp safe?
• Can this webapp be accessed from the mobile browsers?

Mulund College of Commerce (Autonomous) 2023-24 4


Social Media Web Application

4. System Design Details


4.1 Event Table:

No. Event Trigger Source Activity Response Destination

Filling up If successful,
Account details to user will Login
1 Registeration Register User create an navigate to Page.jsx
Or Account login interface
Creation or else error
Filling up If successful,
Account Login respective user will Login
2 Login User email and navigate to Page.jsx
password their profile
interface or else
error
Providing If successful,
a caption content will be
3 Post Content Post User and a file posted and HomePage/
to be visible on the index.jsx
posted interface else
not
Click on On click it will
Like the like the post
4 Like Post icon User icon to and if it was Home
Or Unlike Post ( ) like or previously page.jsx
dislike a liked, it will
post dislike the post
Person Click on Friend List of
Friend Plus the + both the Home
5 Or icon User to Friend accounts will page.jsx
Unfriend ( +) or be updated
Unfriend
Light mode Sun/ Theme of entire
Or Moon User Click on webapp will Home
6 Dark mode icon / change to page.jsx
switch light/dark
mode
Click on The user will Login
Log Out Log Out the logout from the Page.jsx
7 From the User Logout current account
account button

Event Table 1

Mulund College of Commerce (Autonomous) 2023-24 5


Social Media Web Application

4.2 Class Diagram

Figure 1

Mulund College of Commerce (Autonomous) 2023-24 6


Social Media Web Application

4.3 Use Case Diagram

Figure 2

Mulund College of Commerce (Autonomous) 2023-24 7


Social Media Web Application

4.4 Sequence Diagram

Figure 3

Mulund College of Commerce (Autonomous) 2023-24 8


Social Media Web Application

4.5 Activity Diagram

Figure 4

Mulund College of Commerce (Autonomous) 2023-24 9


Social Media Web Application

4.6 State Diagram

Figure 5

4.7 Package Diagram

Figure 6

Mulund College of Commerce (Autonomous) 2023-24 10


Social Media Web Application

4.8 Component Diagram

Figure 7

4.9 Development Diagram

Figure 8

Mulund College of Commerce (Autonomous) 2023-24 11


Social Media Web Application

4.10 Database Design (MongoDB)

4.10.1 Database: test

Figure 9

4.10.2 Collection: posts

Figure 10

Mulund College of Commerce (Autonomous) 2023-24 12


Social Media Web Application

4.10.3 Collection: users

Figure 11

Mulund College of Commerce (Autonomous) 2023-24 13


Social Media Web Application

5. System Implementation

Client
FlexBetween.jsx
import { Box } from "@mui/material";
import { styled } from "@mui/system";

const FlexBetween = styled(Box)({


display:"flex",
justifyContent:'space-between',
alignItems:"center",
});
export default FlexBetween;

Friend.jsx
import { PersonAddOutlined, PersonRemoveOutlined } from "@mui/icons-material";
import { Box, IconButton, Typography, useTheme } from "@mui/material";
import { useDispatch, useSelector } from "react-redux";
import { useNavigate } from "react-router-dom";
import { setFriends } from "state";
import FlexBetween from "./FlexBetween";
import UserImage from "./UserImage";
import { useState } from "react";

const Friend = ({ friendId, name, subtitle, userPicturePath }) => {


const dispatch = useDispatch();
const navigate = useNavigate();
const { _id } = useSelector((state) => state.user);
const token = useSelector((state) => state.token);
const friends = useSelector((state) => state.user.friends);

const { palette } = useTheme();


const primaryLight = palette.primary.light;
const primaryDark = palette.primary.dark;
const main = palette.neutral.main;
const medium = palette.neutral.medium;

const [isAdded, setIsAdded] = useState(false);

const isFriend = friends.find((friend) => friend._id === friendId);

const patchFriend = async () => {

Mulund College of Commerce (Autonomous) 2023-24 14


Social Media Web Application

const response = await fetch(


`http://localhost:3001/users/${_id}/${friendId}`,
{
method: "PATCH",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
}
);
const data = await response.json();
dispatch(setFriends({ friends: data }));
setIsAdded(!isAdded);

setTimeout(() => {
setIsAdded(false);
}, 2000);
};

return (
<FlexBetween>
<FlexBetween gap="1rem">
<UserImage image={userPicturePath} size="55px" />
<Box
onClick={() => {
navigate(`/profile/${friendId}`);
navigate(0);
}}
>
<Typography
color={main}
variant="h5"
fontWeight="500"
sx={{
"&:hover": {
color: palette.primary.light,
cursor: "pointer",
},
}}
>
{name}
</Typography>
<Typography color={medium} fontSize="0.75rem">
{subtitle}

Mulund College of Commerce (Autonomous) 2023-24 15


Social Media Web Application

</Typography>
</Box>
</FlexBetween>
<IconButton
onClick={() => patchFriend()}
sx={{ backgroundColor: primaryLight, p: "0.6rem" }}
>
{isFriend ? (
<PersonRemoveOutlined sx={{ color: primaryDark }} />
):(
<PersonAddOutlined sx={{ color: primaryDark }} />
)}
</IconButton>
{isAdded && (
<Box
position="fixed"
bottom="20px"
left="43%"
transform="translateX(-50%)"
backgroundColor="rgba(0, 0, 0, 0.8)"
color="white"
borderRadius="4px"
padding="20px"
zIndex="100"
textAlign="center"
transition="opacity 0.5s"
fontSize="20px"
>
{isFriend ? "Added to Friend list" : "Removed from Friend list"}
</Box>

)}
</FlexBetween>
);
};
export default Friend;

UserImage.jsx
import { Box } from "@mui/material";
const UserImage=({ image,size="60px"}) => {
return(
<Box width={size} height={size}>
<img
style={{objectFit:"cover",borderRadius:"50%"}}

Mulund College of Commerce (Autonomous) 2023-24 16


Social Media Web Application

width={size}
height={size}
alt="user"
src={`http://localhost:3001/assets/${image}`}>
</img>
</Box>
)
}
export default UserImage;

WidgetWrapper.jsx
import styled from "@emotion/styled";
import { Box } from "@mui/material";

const WidgetWrapper = styled(Box)(({theme}) => ({


padding:"1.5rem 1.5rem 0.75rem 1.5rem",
backgroundColor: theme.palette.background.alt,
borderRadius:"0.75rem"
}));

export default WidgetWrapper;

homepage → index.jsx
import NavBar from "scenes/navbar";
import { Box, useMediaQuery } from "@mui/material";
import { useSelector } from "react-redux";
import UserWidget from "scenes/widgets/UserWidget";
import MyPostWidget from "scenes/widgets/MyPostWidget";
import PostsWidget from "scenes/widgets/PostsWidget";
import AdvertWidget from "scenes/widgets/AdverWidget";
import FriendListWidget from "scenes/widgets/FriendListWidget";

const HomePage = () => {


const isNonMobileScreen = useMediaQuery("(min-width:1000px)");
const { _id, picturePath } = useSelector((state) => state.user);

return (

<Box>
<NavBar />
<Box
width="100%"
padding="2rem"

Mulund College of Commerce (Autonomous) 2023-24 17


Social Media Web Application

display={isNonMobileScreen ? "flex" : "block"}


gap="0.5rem"
justifyContent="space-between">
<Box flexBasis={isNonMobileScreen ? "26%" : undefined}>
<UserWidget userId={_id} picturePath={picturePath} />
</Box>
<Box
flexBasis={isNonMobileScreen ? "42%" : undefined}
mt={isNonMobileScreen ? undefined : "2rem"}
>
<Box height="5rem"></Box>
<MyPostWidget picturePath={picturePath} />
<PostsWidget userId={_id} />
</Box>
{isNonMobileScreen && (
<Box flexBasis="26%">
<Box height="5rem"></Box>
<AdvertWidget />
<Box m="2rem 0" />
<FriendListWidget userId={_id} />
</Box>
)}
</Box>
</Box>
);
};
export default HomePage;

loginPage→Form.jsx
import { useState } from "react";
import {
Box,
Button,
TextField,
useMediaQuery,
Typography,
useTheme,
Snackbar,
SnackbarContent
} from "@mui/material";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import { Formik } from "formik";
import * as yup from "yup";
import { useNavigate } from "react-router-dom";

Mulund College of Commerce (Autonomous) 2023-24 18


Social Media Web Application

import { useDispatch } from "react-redux";


import { setLogin } from "state";
import Dropzone from "react-dropzone";
import FlexBetween from "components/FlexBetween";

const registerSchema = yup.object().shape({


firstName: yup.string().required("required"),
lastName: yup.string().required("required"),
email: yup.string().email("invalid email").required("required"),
password: yup.string().required("required"),
location: yup.string().required("required"),
occupation: yup.string().required("required"),
picture: yup.string().required("required"),
});

const loginSchema = yup.object().shape({


email: yup.string().email("invalid email").required("required"),
password: yup.string().required("required"),
});

const initialValuesRegister = {
firstName: "",
lastName: "",
email: "",
password: "",
location: "",
occupation: "",
picture: "",
};

const initialValuesLogin = {
email: "",
password: "",
};

const Form = () => {


const [pageType, setPageType] = useState("login");
const [isRegistrationSuccess, setRegistrationSuccess] = useState(false);
const [registerMessage, setRegisterMessage] = useState("");

const theme = useTheme();


const { palette } = useTheme();
const dispatch = useDispatch();
const navigate = useNavigate();

Mulund College of Commerce (Autonomous) 2023-24 19


Social Media Web Application

const isNonMobile = useMediaQuery("(min-width:600px)");


const isLogin = pageType === "login";
const isRegister = pageType === "register";

const register = async (values, onSubmitProps) => {


// this allows us to send form info with image
const formData = new FormData();
for (let value in values) {
formData.append(value, values[value]);
}
formData.append("picturePath", values.picture.name);

const savedUserResponse = await fetch(


"http://localhost:3001/auth/register",
{
method: "POST",
body: formData,
}
);
const savedUser = await savedUserResponse.json();
onSubmitProps.resetForm();

if (savedUser) {
setRegistrationSuccess(true);
setRegisterMessage("Tea is Ready: Successfully Registered");
onSubmitProps.resetForm();
setPageType("login");
}
};

const login = async (values, onSubmitProps) => {


const loggedInResponse = await fetch("http://localhost:3001/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(values),
});
const loggedIn = await loggedInResponse.json();
onSubmitProps.resetForm();
if (loggedIn) {
dispatch(
setLogin({
user: loggedIn.user,
token: loggedIn.token,
})

Mulund College of Commerce (Autonomous) 2023-24 20


Social Media Web Application

);
navigate("/home");
onSubmitProps.resetForm();
}
};

const handleFormSubmit = async (values, onSubmitProps) => {


if (isLogin) await login(values, onSubmitProps);
if (isRegister) await register(values, onSubmitProps);
};

return (
<Formik
onSubmit={handleFormSubmit}
initialValues={isLogin ? initialValuesLogin : initialValuesRegister}
validationSchema={isLogin ? loginSchema : registerSchema}
>
{({
values,
errors,
touched,
handleBlur,
handleChange,
handleSubmit,
setFieldValue,
resetForm,
}) => (
<form onSubmit={handleSubmit}>
<Box
display="grid"
gap="30px"
gridTemplateColumns="repeat(4, minmax(0, 1fr))"
sx={{
"& > div": { gridColumn: isNonMobile ? undefined : "span 4" },
}}
>
{isRegister && (
<>
<TextField
label="First Name"
onBlur={handleBlur}
onChange={handleChange}
value={values.firstName}
name="firstName"

Mulund College of Commerce (Autonomous) 2023-24 21


Social Media Web Application

error={
Boolean(touched.firstName) && Boolean(errors.firstName)
}
helperText={touched.firstName && errors.firstName}
sx={{ gridColumn: "span 2" }}
/>
<TextField
label="Last Name"
onBlur={handleBlur}
onChange={handleChange}
value={values.lastName}
name="lastName"
error={Boolean(touched.lastName) && Boolean(errors.lastName)}
helperText={touched.lastName && errors.lastName}
sx={{ gridColumn: "span 2" }}
/>
<TextField
label="Location"
onBlur={handleBlur}
onChange={handleChange}
value={values.location}
name="location"
error={Boolean(touched.location) && Boolean(errors.location)}
helperText={touched.location && errors.location}
sx={{ gridColumn: "span 4" }}
/>
<TextField
label="Occupation"
onBlur={handleBlur}
onChange={handleChange}
value={values.occupation}
name="occupation"
error={
Boolean(touched.occupation) && Boolean(errors.occupation)
}
helperText={touched.occupation && errors.occupation}
sx={{ gridColumn: "span 4" }}
/>
<Box
gridColumn="span 4"
border={`1px solid ${palette.neutral.medium}`}
borderRadius="5px"
p="1rem"
>

Mulund College of Commerce (Autonomous) 2023-24 22


Social Media Web Application

<Dropzone
acceptedFiles=".jpg,.jpeg,.png"
multiple={false}
onDrop={(acceptedFiles) =>
setFieldValue("picture", acceptedFiles[0])
}
>
{({ getRootProps, getInputProps }) => (
<Box
{...getRootProps()}
border={`2px dashed ${palette.primary.main}`}
p="1rem"
sx={{ "&:hover": { cursor: "pointer" } }}
>
<input {...getInputProps()} />
{!values.picture ? (
<p>Add Picture Here</p>
):(
<FlexBetween>
<Typography>{values.picture.name}</Typography>
<EditOutlinedIcon />
</FlexBetween>
)}
</Box>
)}
</Dropzone>
</Box>
</>
)}

<TextField
label="Email"
onBlur={handleBlur}
onChange={handleChange}
value={values.email}
name="email"
error={Boolean(touched.email) && Boolean(errors.email)}
helperText={touched.email && errors.email}
sx={{ gridColumn: "span 4" }}
/>
<TextField
label="Password"
type="password"
onBlur={handleBlur}

Mulund College of Commerce (Autonomous) 2023-24 23


Social Media Web Application

onChange={handleChange}
value={values.password}
name="password"
error={Boolean(touched.password) && Boolean(errors.password)}
helperText={touched.password && errors.password}
sx={{ gridColumn: "span 4" }}
/>
</Box>

{/* BUTTONS */}


<Box>
<Button
fullWidth
type="submit"
sx={{
m: "2rem 0",
p: "1rem",
backgroundColor: palette.primary.main,
color: palette.background.alt,
"&:hover": { color: palette.primary.main },
}}
>
{isLogin ? "LOGIN" : "REGISTER"}
</Button>
<Typography
onClick={() => {
setPageType(isLogin ? "register" : "login");
resetForm();
}}
sx={{
textDecoration: "underline",
color: palette.primary.main,
"&:hover": {
cursor: "pointer",
color: palette.primary.light,
},
}}
>
{isLogin
? "Don't have an account? Sign Up here."
: "Already have an account? Login here."}
</Typography>
</Box>
{/* Snackbar for Registration Success */}

Mulund College of Commerce (Autonomous) 2023-24 24


Social Media Web Application

<Snackbar
open={isRegistrationSuccess}
onClose={() => setRegistrationSuccess(false)}
autoHideDuration={2000}
>
<SnackbarContent
message={
<Box
display="flex"
alignItems="center"
justifyContent="center"
p="1rem"
border={`0.5px solid ${theme.palette.primary.main}`}
borderRadius="5px"
bgcolor={theme.palette.background.alt}
color={theme.palette.primary.main}

>
{registerMessage}
</Box>
}
/>
</Snackbar>

</form>
)}
</Formik>
);
};
export default Form;

loginPage →index.jsx
import { Box, Typography, useTheme, useMediaQuery } from "@mui/material";
import Form from "./Form";

const LoginPage = () => {

const theme = useTheme();


const isNonMobileScreens = useMediaQuery("(min-width: 100px)");
return (
<center>
<Box>
<Box
width="100%"

Mulund College of Commerce (Autonomous) 2023-24 25


Social Media Web Application

backgroundColor={theme.palette.background.alt}
p="1rem 6%"
texAlign="center">
<Typography
fontWeight="bold"
fontSize="clamp(1rem,2rem,2.25rem)"
color="primary"
>
WISE
</Typography>
</Box>

<Box
width={isNonMobileScreens ? "50%" : "93%"}
p="2rem"
m="2rem auto"
borderRadius="1.5rem"
backgroundColor={theme.palette.background.alt}
>
<Typography
fontWeight="500"
variant="h5"
sx={{mb: "1.5rem"}}>
Spill the Tea and use us for free
</Typography>
<Form></Form>
</Box>
</Box>
</center>
);
};
export default LoginPage;

navbar → index.jsx
import { useState } from "react";
import {
Box,
IconButton,
InputBase,
Typography,
Select,
MenuItem,
FormControl,
useTheme,

Mulund College of Commerce (Autonomous) 2023-24 26


Social Media Web Application

useMediaQuery,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Button
} from "@mui/material";
import {
Search,
Message,
DarkMode,
LightMode,
Notifications,
Help,
Menu,
Close
} from "@mui/icons-material";

import { useDispatch, useSelector } from "react-redux";


import { setMode, setLogout } from "state";
import { useNavigate } from "react-router-dom";
import FlexBetween from "components/FlexBetween";

const NavBar = () => {


const [isMobileMenuToggled, setIsMobileMenuToggled] = useState(false);
const dispatch = useDispatch();
const navigate = useNavigate();
const user = useSelector((state) => state.user);
const isNonMobileScreens = useMediaQuery("(min-width: 100px)");

const [openLogoutDialog, setOpenLogoutDialog] = useState(false);


const [showTeaMessage, setShowTeaMessage] = useState(false);

const theme = useTheme();


const neutralLight = theme.palette.neutral.light;
const dark = theme.palette.neutral.dark;
const background = theme.palette.background.default;
const primaryLight = theme.palette.primary.light;
const alt = theme.palette.background.alt;

const fullName = `${user.firstName} ${user.lastName}`;

const handleLogout = () => {

Mulund College of Commerce (Autonomous) 2023-24 27


Social Media Web Application

console.log("Log out clikced !")


setOpenLogoutDialog(true);
};

const handleConfirmLogout = () => {


setOpenLogoutDialog(false);
dispatch(setLogout());
};

const handleCloseLogoutDialog = () => {


setOpenLogoutDialog(false);
// Show the tea message and start the timeout
setShowTeaMessage(true);
setTimeout(() => {
setShowTeaMessage(false);
}, 2000); // Hide the message after 2 seconds
};

return (
<div
style={{
position: "fixed",
top: 0,
left: 0,
width: "100%",
zIndex: 100,
backgroundColor: alt,
}}
>
<FlexBetween padding="1rem 6%" backgroundColor={alt}>
<FlexBetween gap="1.7rem">
<Typography
fontWeight="bold"
fontSize="clamp(1rem,2rem,2.25rem)"
color="primary"
onClick={() => navigate("/home")}
sx={{
"&:hover": {
color: primaryLight,
cursor: "pointer",
},
}}
>
WISE

Mulund College of Commerce (Autonomous) 2023-24 28


Social Media Web Application

</Typography>
{isNonMobileScreens && (
<FlexBetween
backgroundColor={neutralLight}
borderRadius="9px"
gap='3rem'
padding="0.1rem 1.5rem">
<InputBase placeholder="Search..." />
<IconButton>
<Search />
</IconButton>
</FlexBetween>
)}
</FlexBetween>
{// DESKTOP NAV
}
{isNonMobileScreens ?
(<FlexBetween gap="2rem">
<IconButton onClick={() => dispatch(setMode())}>
{theme.palette.mode === "dark" ? (
<DarkMode sx={{ fontSize: "25px" }} />
):(
<LightMode sx={{ color: dark, fontSize: "25px" }} />
)}
</IconButton>
<Message sx={{ fontSize: "25px" }} />
<Notifications sx={{ fontSize: "25px" }} />
<Help sx={{ fontSize: "25px" }} />
<FormControl variant="standard" value={fullName}>
<Select
value={fullName}
sx={{
backgroundColor: neutralLight,
width: "175px",
borderRadius: "0.25rem",
p: "0.25rem 1rem",
"& .MuiSvgIcon-root": {
pr: "0.25rem",
width: "3rem"
},
"& .MuiSelect-select:focus": {
backgroundColor: neutralLight
}
}}

Mulund College of Commerce (Autonomous) 2023-24 29


Social Media Web Application

input={<InputBase />}
>
<MenuItem value={fullName}>
<Typography>{fullName}</Typography>
</MenuItem>
<MenuItem onClick={handleLogout}>Log Out</MenuItem>
</Select>
</FormControl>
</FlexBetween>
)
:
(
<IconButton onClick={() => setIsMobileMenuToggled(!isMobileMenuToggled)}
>
<Menu />
</IconButton>)}

{/* MOBILE NAV */}


{!isNonMobileScreens && isMobileMenuToggled && (
<Box
position="fixed"
right="0"
bottom="0"
height="100%"
zIndex="10"
maxWidth="500px"
minWidth="300px"
backgroundColor={background}
>
{/* CLOSE ICON */}
<Box display="flex" justifyContent="flex-end" p="1rem">
<IconButton
onClick={() => setIsMobileMenuToggled(!isMobileMenuToggled)}
>
<Close />
</IconButton>
</Box>

{/* MENU ITEMS */}


<FlexBetween
display="flex"
flexDirection="column"
justifyContent="center"
alignItems="center"

Mulund College of Commerce (Autonomous) 2023-24 30


Social Media Web Application

gap="3rem"
>
<IconButton
onClick={() => dispatch(setMode())}
sx={{ fontSize: "25px" }}
>
{theme.palette.mode === "dark" ? (
<DarkMode sx={{ fontSize: "25px" }} />
):(
<LightMode sx={{ color: dark, fontSize: "25px" }} />
)}
</IconButton>
<Message sx={{ fontSize: "25px" }} />
<Notifications sx={{ fontSize: "25px" }} />
<Help sx={{ fontSize: "25px" }} />
<FormControl variant="standard" value={fullName}>
<Select
value={fullName}
sx={{
backgroundColor: neutralLight,
width: "150px",
borderRadius: "0.25rem",
p: "0.25rem 1rem",
"& .MuiSvgIcon-root": {
pr: "0.25rem",
width: "3rem",
},
"& .MuiSelect-select:focus": {
backgroundColor: neutralLight,
},
}}
input={<InputBase />}
>
<MenuItem value={fullName}>
<Typography>{fullName}</Typography>
</MenuItem>
<MenuItem onClick={handleLogout}>Log Out</MenuItem>
</Select>
</FormControl>
</FlexBetween>
</Box>
)}
{/* Logout Confirmation Dialog */}
<Dialog

Mulund College of Commerce (Autonomous) 2023-24 31


Social Media Web Application

open={openLogoutDialog}
onClose={handleCloseLogoutDialog}
maxWidth="sm" /* Adjust maxWidth for width */
fullWidth /* Set fullWidth to use full available width */
>
<DialogTitle>Confirm Logout</DialogTitle>
<DialogContent>
<DialogContentText sx={{ fontSize: "20px" /* Adjust font size */ }}>
Are you sure you want to log out?
</DialogContentText>
</DialogContent>
<DialogActions sx={{ fontSize: "20px" /* Adjust font size */ }}>
<Button onClick={handleCloseLogoutDialog} color="primary">
Cancel
</Button>
<Button onClick={handleConfirmLogout} color="primary">
Confirm
</Button>
</DialogActions>
</Dialog>
{/* Logout Cancelling Message */}
{showTeaMessage && (
<Box
position="fixed"
bottom="20px"
left="38%"
transform="translateX(-50%)"
backgroundColor="rgba(0, 0, 0, 0.8)"
color="white"
borderRadius="4px"
padding="20px"
zIndex="100"
textAlign="center"
transition="opacity 0.5s"
fontSize="20px"
>
Please continue spilling the tea ! :)
</Box>
)}
</FlexBetween>
</div>
);
};
export default NavBar;

Mulund College of Commerce (Autonomous) 2023-24 32


Social Media Web Application

profilePage → index.jsx

import { Box, useMediaQuery } from "@mui/material";


import { useEffect, useState } from "react";
import { useSelector } from "react-redux";
import { useParams } from "react-router-dom";
import Navbar from "scenes/navbar";
import FriendListWidget from "scenes/widgets/FriendListWidget";
import PostsWidget from "scenes/widgets/PostsWidget";
import UserWidget from "scenes/widgets/UserWidget";

const ProfilePage = () => {


const [user, setUser] = useState(null);
const { userId } = useParams();
const token = useSelector((state) => state.token);
const isNonMobileScreens = useMediaQuery("(min-width:1000px)");

const getUser = async () => {


const response = await fetch(`http://localhost:3001/users/${userId}`, {
method: "GET",
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
setUser(data);
};

useEffect(() => {
getUser();
}, []); // eslint-disable-line react-hooks/exhaustive-deps

if (!user) return null;

return (
<Box>
<Navbar />
<Box
width="100%"
padding="2rem 6%"
display={isNonMobileScreens ? "flex" : "block"}
gap="2rem"
justifyContent="center"

Mulund College of Commerce (Autonomous) 2023-24 33


Social Media Web Application

>
<Box flexBasis={isNonMobileScreens ? "26%" : undefined}>
<UserWidget userId={userId} picturePath={user.picturePath} />
</Box>
<Box
flexBasis={isNonMobileScreens ? "42%" : undefined}
mt={isNonMobileScreens ? undefined : "2rem"}
>
<Box m="5rem 0" />
<PostsWidget userId={userId} isProfile />
</Box>
<Box flexBasis={isNonMobileScreens ? "26%" : undefined}>
<FriendListWidget userId={userId} />
</Box>
</Box>
</Box>
);
};
export default ProfilePage;

widgets
AdverWidget.jsx
import { Typography, useTheme } from "@mui/material";
import FlexBetween from "components/FlexBetween";
import WidgetWrapper from "components/WidgetWrapper";

const AdvertWidget = () => {


const { palette } = useTheme();
const dark = palette.neutral.dark;
const main = palette.neutral.main;
const medium = palette.neutral.medium;

return (
<WidgetWrapper>
<FlexBetween>
<Typography color={dark} variant="h5" fontWeight="500">
Sponsored
</Typography>
<Typography color={medium}>Create Ad</Typography>
</FlexBetween>
<img
width="100%"
height="auto"
alt="advert"

Mulund College of Commerce (Autonomous) 2023-24 34


Social Media Web Application

src="http://localhost:3001/assets/info4.jpeg"
style={{ borderRadius: "0.75rem", margin: "0.75rem 0" }}
/>
<FlexBetween>
<Typography color={main}>MikaCosmetics</Typography>
<Typography color={medium}>mikacosmetics.com</Typography>
</FlexBetween>
<Typography color={medium} m="0.5rem 0">
Your pathway to stunning and immaculate beauty and made sure your skin
is exfoliating skin and shining like light.
</Typography>
</WidgetWrapper>
);
};
export default AdvertWidget;

FriendListWidget.jsx
import { Box, Typography, useTheme } from "@mui/material";
import Friend from "components/Friend";
import WidgetWrapper from "components/WidgetWrapper";
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setFriends } from "state";

const FriendListWidget = ({ userId }) => {


const dispatch = useDispatch();
const { palette } = useTheme();
const token = useSelector((state) => state.token);
const friends = useSelector((state) => state.user.friends);

const getFriends = async () => {


const response = await fetch(
`http://localhost:3001/users/${userId}/friends`,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await response.json();
dispatch(setFriends({ friends: data }));
};

useEffect(() => {
getFriends();

Mulund College of Commerce (Autonomous) 2023-24 35


Social Media Web Application

}, []); // eslint-disable-line react-hooks/exhaustive-deps

return (
<div
style={{
position: "sticky",
top: "7rem",
zIndex: 100,
}}
>
<WidgetWrapper
style={{
maxHeight: "30rem", // Adjust as needed
overflowY: "auto",
}}
>
<Typography
color={palette.neutral.dark}
variant="h5"
fontWeight="500"
sx={{ mb: "1.5rem" }}
>
Friend List
</Typography>
<Box display="flex" flexDirection="column" gap="1.5rem">
{friends.map((friend) => (
<Friend
key={friend._id}
friendId={friend._id}
name={`${friend.firstName} ${friend.lastName}`}
subtitle={friend.occupation}
userPicturePath={friend.picturePath}
/>
))}
</Box>

</WidgetWrapper>
</div>
);
};
export default FriendListWidget;

MyPostWidget.jsx
import {

Mulund College of Commerce (Autonomous) 2023-24 36


Social Media Web Application

EditOutlined,
DeleteOutlined,
AttachFileOutlined,
GifBoxOutlined,
ImageOutlined,
MicOutlined,
MoreHorizOutlined,
} from "@mui/icons-material";
import {
Box,
Divider,
Typography,
InputBase,
useTheme,
Button,
IconButton,
useMediaQuery,
} from "@mui/material";
import FlexBetween from "components/FlexBetween";
import Dropzone from "react-dropzone";
import UserImage from "components/UserImage";
import WidgetWrapper from "components/WidgetWrapper";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setPosts } from "state";

const MyPostWidget = ({ picturePath }) => {


const dispatch = useDispatch();
const [isImage, setIsImage] = useState(false);
const [image, setImage] = useState(null);
const [post, setPost] = useState("");
const { palette } = useTheme();
const { _id } = useSelector((state) => state.user);
const token = useSelector((state) => state.token);
const isNonMobileScreens = useMediaQuery("(min-width: 1000px)");
const mediumMain = palette.neutral.mediumMain;
const medium = palette.neutral.medium;

const [isImagePosted, setImagePosted] = useState(false);

const handlePost = async () => {


const formData = new FormData();
formData.append("userId", _id);
formData.append("description", post);

Mulund College of Commerce (Autonomous) 2023-24 37


Social Media Web Application

if (image) {
formData.append("picture", image);
formData.append("picturePath", image.name);
}

const response = await fetch(`http://localhost:3001/posts`, {


method: "POST",
headers: { Authorization: `Bearer ${token}` },
body: formData,
});
const posts = await response.json();
dispatch(setPosts({ posts }));
setImage(null);
setPost("");
setImagePosted(true);
setTimeout(()=>{
setImagePosted(false);
},2500)
};

return (
<WidgetWrapper>
<FlexBetween gap="1.5rem">
<UserImage image={picturePath} />
<InputBase
placeholder="What's on your mind..."
onChange={(e) => setPost(e.target.value)}
value={post}
sx={{
width: "100%",
backgroundColor: palette.neutral.light,
borderRadius: "2rem",
padding: "1rem 2rem",
}}
/>
</FlexBetween>
{isImage && (
<Box
border={`1px solid ${medium}`}
borderRadius="5px"
mt="1rem"
p="1rem"
>
<Dropzone

Mulund College of Commerce (Autonomous) 2023-24 38


Social Media Web Application

acceptedFiles=".jpg,.jpeg,.png"
multiple={false}
onDrop={(acceptedFiles) => setImage(acceptedFiles[0])}
>
{({ getRootProps, getInputProps }) => (
<FlexBetween>
<Box
{...getRootProps()}
border={`2px dashed ${palette.primary.main}`}
p="1rem"
width="100%"
sx={{ "&:hover": { cursor: "pointer" } }}
>
<input {...getInputProps()} />
{!image ? (
<p>Add Image Here</p>
):(
<FlexBetween>
<Typography>{image.name}</Typography>
<EditOutlined />
</FlexBetween>
)}
</Box>
{image && (
<IconButton
onClick={() => setImage(null)}
sx={{ width: "15%" }}
>
<DeleteOutlined />
</IconButton>
)}
</FlexBetween>
)}
</Dropzone>
</Box>
)}

<Divider sx={{ margin: "1.25rem 0" }} />

<FlexBetween>
<FlexBetween gap="0.25rem" onClick={() => setIsImage(!isImage)}>
<ImageOutlined sx={{ color: mediumMain }} />
<Typography
color={mediumMain}

Mulund College of Commerce (Autonomous) 2023-24 39


Social Media Web Application

sx={{ "&:hover": { cursor: "pointer", color: medium } }}


>
Image
</Typography>
</FlexBetween>

{isNonMobileScreens ? (
<>
<FlexBetween gap="0.25rem">
<GifBoxOutlined sx={{ color: mediumMain }} />
<Typography color={mediumMain}>Clip</Typography>
</FlexBetween>

<FlexBetween gap="0.25rem">
<AttachFileOutlined sx={{ color: mediumMain }} />
<Typography color={mediumMain}>Attachment</Typography>
</FlexBetween>

<FlexBetween gap="0.25rem">
<MicOutlined sx={{ color: mediumMain }} />
<Typography color={mediumMain}>Audio</Typography>
</FlexBetween>
</>
):(
<FlexBetween gap="0.25rem">
<MoreHorizOutlined sx={{ color: mediumMain }} />
</FlexBetween>
)}

<Button
disabled={!post}
onClick={handlePost}
sx={{
color: palette.background.alt,
backgroundColor: palette.primary.main,
borderRadius: "3rem",
}}
>
POST
</Button>
</FlexBetween>

{/* Post uploaded message */}


{

Mulund College of Commerce (Autonomous) 2023-24 40


Social Media Web Application

isImagePosted && (
<Box
position="fixed"
bottom="20px"
left="43%"
transform="translateX(-50%)"
backgroundColor="rgba(0, 0, 0, 0.8)"
color="white"
borderRadius="4px"
padding="20px"
zIndex="100"
textAlign="center"
transition="opacity 0.5s"
fontSize="20px"
>
Post Uploaded !
</Box>
)

}
</WidgetWrapper>
);
};
export default MyPostWidget;

PostsWidget.jsx
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setPosts } from "state";
import PostWidget from "./PostWidget";

const PostsWidget = ({ userId, isProfile = false }) => {


const dispatch = useDispatch();
const posts = useSelector((state) => state.posts);
const token = useSelector((state) => state.token);

const getPosts = async () => {


const response = await fetch("http://localhost:3001/posts", {
method: "GET",
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
dispatch(setPosts({ posts: data }));
};

Mulund College of Commerce (Autonomous) 2023-24 41


Social Media Web Application

const getUserPosts = async () => {


const response = await fetch(
`http://localhost:3001/posts/${userId}/posts`,
{
method: "GET",
headers: { Authorization: `Bearer ${token}` },
}
);
const data = await response.json();
dispatch(setPosts({ posts: data }));
};

useEffect(() => {
if (isProfile) {
getUserPosts();
} else {
getPosts();
}
}, [posts]); // eslint-disable-line react-hooks/exhaustive-deps
const postsArray = Array.from(posts);

return (
<>
{postsArray.map(
({
_id,
userId,
firstName,
lastName,
description,
location,
picturePath,
userPicturePath,
likes,
comments,
}) => (
<PostWidget
key={_id}
postId={_id}
postUserId={userId}
name={`${firstName} ${lastName}`}
description={description}
location={location}

Mulund College of Commerce (Autonomous) 2023-24 42


Social Media Web Application

picturePath={picturePath}
userPicturePath={userPicturePath}
likes={likes}
comments={comments}
/>
)
)}
</>
);
};
export default PostsWidget;

PostWidget.jsx
import React, { useState } from "react";
import {
IconButton,
Button,
Input,
Typography,
useTheme,
Box,
Divider,
} from "@mui/material";
import {
ChatBubbleOutlineOutlined,
FavoriteBorderOutlined,
FavoriteOutlined,
ShareOutlined,
} from "@mui/icons-material";
import WidgetWrapper from "components/WidgetWrapper";
import Friend from "components/Friend";
import FlexBetween from "components/FlexBetween";
import { useDispatch, useSelector } from "react-redux";
import { setPost } from "state";

const PostWidget = ({
postId,
postUserId,
name,
description,
location,
picturePath,
userPicturePath,
likes,

Mulund College of Commerce (Autonomous) 2023-24 43


Social Media Web Application

comments,
}) => {
const [isComments, setIsComments] = useState(false);
const [newComment, setNewComment] = useState("");

const dispatch = useDispatch();


const token = useSelector((state) => state.token);
const loggedInUserId = useSelector((state) => state.user._id);
const isLiked = Boolean(likes[loggedInUserId]);
const likeCount = Object.keys(likes).length;

const { palette } = useTheme();


const main = palette.neutral.main;
const primary = palette.primary.main;

const patchLike = async () => {


const response = await fetch(`http://localhost:3001/posts/${postId}/like`, {
method: "PATCH",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ userId: loggedInUserId }),
});
const updatedPost = await response.json();
dispatch(setPost({ post: updatedPost }));
};
const handlePostComment = async () => {
if (!loggedInUserId) {
// Redirect user to the login page
window.location.href = "/login";
return;
}

try {
const requestBody = {
id: postId,
userId: loggedInUserId,
comment: newComment,
};
setNewComment("");

const response = await fetch(


`http://localhost:3001/posts/${postId}/comments`,

Mulund College of Commerce (Autonomous) 2023-24 44


Social Media Web Application

{
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(requestBody),
}
);

if (response.ok) {
const updatedPost = await response.json();
dispatch(setPost({ post: updatedPost }));
} else {
console.error("Error posting comment");
}
} catch (error) {
console.error("An error occurred:", error);
}
};

return (
<WidgetWrapper m="2rem 0">
<Friend
friendId={postUserId}
name={name}
subtitle={location}
userPicturePath={userPicturePath}
/>
<Typography color={main} sx={{ mt: "1rem" }}>
{description}
</Typography>
{picturePath && (
<img
width="100%"
height="auto"
alt="post"
style={{ borderRadius: "0.75rem", marginTop: "0.75rem" }}
src={`http://localhost:3001/assets/${picturePath}`}
/>
)}
<FlexBetween mt="0.25rem">
<FlexBetween gap="1rem">
<FlexBetween gap="0.3rem">

Mulund College of Commerce (Autonomous) 2023-24 45


Social Media Web Application

<IconButton onClick={patchLike}>
{isLiked ? (
<FavoriteOutlined sx={{ color: primary }} />
):(
<FavoriteBorderOutlined />
)}
</IconButton>
<Typography>{likeCount}</Typography>
</FlexBetween>

<FlexBetween gap="0.3rem">
<IconButton onClick={() => setIsComments(!isComments)}>
<ChatBubbleOutlineOutlined />
</IconButton>
<Typography>{comments.length}</Typography>
</FlexBetween>
</FlexBetween>

<IconButton>
<ShareOutlined />
</IconButton>
</FlexBetween>
{isComments && (
<Box mt="0.5rem">
{comments.map((comment, i) => (
<Box key={`${name}-${i}`}>
<Divider />
<Typography sx={{ color: main, m: "0.5rem 0", pl: "1rem" }}>
{comment.comment}
</Typography>
</Box>
))}
<Divider />
<Input
placeholder="Write a comment..."
value={newComment}
onChange={(e) => setNewComment(e.target.value)}
sx={{ marginBottom: "1rem", marginTop:"0.5rem" }}
/>
<Button
onClick={handlePostComment}
sx={{
left:"2rem",
padding:"0.1rem",

Mulund College of Commerce (Autonomous) 2023-24 46


Social Media Web Application

color: palette.background.alt,
backgroundColor: palette.primary.main,
borderRadius: "3rem",
}}>
Post
</Button>
</Box>
)}
</WidgetWrapper>
);
};
export default PostWidget;

UserWidget.jsx
import {
ManageAccountsOutlined,
EditOutlined,
LocationOnOutlined,
WorkOutlineOutlined,
} from "@mui/icons-material";
import { Box, Typography, Divider, useTheme } from "@mui/material";
import UserImage from "components/UserImage";
import FlexBetween from "components/FlexBetween";
import WidgetWrapper from "components/WidgetWrapper";
import { useSelector } from "react-redux";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";

const UserWidget = ({ userId, picturePath }) => {


const [user, setUser] = useState(null);
const { palette } = useTheme();
const navigate = useNavigate();
const token = useSelector((state) => state.token);
const dark = palette.neutral.dark;
const medium = palette.neutral.medium;
const main = palette.neutral.main;

const getUser = async () => {


const response = await fetch(`http://localhost:3001/users/${userId}`, {
method: "GET",
headers: { Authorization: `Bearer ${token}` },
});
const data = await response.json();
setUser(data);

Mulund College of Commerce (Autonomous) 2023-24 47


Social Media Web Application

};

useEffect(() => {
getUser();
}, []); // eslint-disable-line react-hooks/exhaustive-deps

if (!user) {
return null;
}

const {
firstName,
lastName,
location,
occupation,
viewedProfile,
impressions,
friends,
} = user;

return (
<div
style={{
position: "sticky",
top: "7rem",
zIndex: 100,
}}
>
<WidgetWrapper>
{/* FIRST ROW */}
<FlexBetween
gap="0.5rem"
pb="1.1rem"
onClick={() => navigate(`/profile/${userId}`)}
>
<FlexBetween gap="1rem">
<UserImage image={picturePath} />
<Box>
<Typography
variant="h4"
color={dark}
fontWeight="500"
sx={{
"&:hover": {

Mulund College of Commerce (Autonomous) 2023-24 48


Social Media Web Application

color: palette.primary.light,
cursor: "pointer",
},
}}
>
{firstName} {lastName}
</Typography>
<Typography color={medium}>{friends.length} friends</Typography>
</Box>
</FlexBetween>
<ManageAccountsOutlined />
</FlexBetween>

<Divider />

{/* SECOND ROW */}


<Box p="1rem 0">
<Box display="flex" alignItems="center" gap="1rem" mb="0.5rem">
<LocationOnOutlined fontSize="large" sx={{ color: main }} />
<Typography color={medium}>{location}</Typography>
</Box>
<Box display="flex" alignItems="center" gap="1rem">
<WorkOutlineOutlined fontSize="large" sx={{ color: main }} />
<Typography color={medium}>{occupation}</Typography>
</Box>
</Box>

<Divider />

{/* THIRD ROW */}


<Box p="1rem 0">
<FlexBetween mb="0.5rem">
<Typography color={medium}>Who's viewed your profile</Typography>
<Typography color={main} fontWeight="500">
{viewedProfile}
</Typography>
</FlexBetween>
<FlexBetween>
<Typography color={medium}>Impressions of your post</Typography>
<Typography color={main} fontWeight="500">
{impressions}
</Typography>
</FlexBetween>
</Box>

Mulund College of Commerce (Autonomous) 2023-24 49


Social Media Web Application

<Divider />

{/* FOURTH ROW */}


<Box p="1rem 0">
<Typography fontSize="1rem" color={main} fontWeight="500" mb="1rem">
Social Profiles
</Typography>

<FlexBetween gap="1rem" mb="0.5rem">


<FlexBetween gap="1rem">
<img src="../assets/twitter.png" alt="twitter" />
<Box>
<Typography color={main} fontWeight="500">
Twitter
</Typography>
<Typography color={medium}>Social Network</Typography>
</Box>
</FlexBetween>
<EditOutlined sx={{ color: main }} />
</FlexBetween>

<FlexBetween gap="1rem">
<FlexBetween gap="1rem">
<img src="../assets/linkedin.png" alt="linkedin" />
<Box>
<Typography color={main} fontWeight="500">
Linkedin
</Typography>
<Typography color={medium}>Network Platform</Typography>
</Box>
</FlexBetween>
<EditOutlined sx={{ color: main }} />
</FlexBetween>
</Box>
</WidgetWrapper>
</div>
);
};
export default UserWidget;

state → index.js
import { createSlice } from "@reduxjs/toolkit";

Mulund College of Commerce (Autonomous) 2023-24 50


Social Media Web Application

const initialState = {
mode: "light",
user: null,
token: null,
posts: [],
};

export const authSlice = createSlice({


name: "auth",
initialState,
reducers: {
setMode: (state) => {
state.mode = state.mode === "light" ? "dark" : "light";
},
setLogin: (state, action) => {
state.user = action.payload.user;
state.token = action.payload.token;
},
setLogout: (state) => {
state.user = null;
state.token = null;
},
setFriends: (state, action) => {
if (state.user) {
state.user.friends = action.payload.friends;
} else {
console.error("user friends non-existent :(");
}
},
setPosts: (state, action) => {
state.posts = action.payload.posts;
},
setPost: (state, action) => {
const updatedPosts = state.posts.map((post) => {
if (post._id === action.payload.post._id) return action.payload.post;
return post;
});
state.posts = updatedPosts;
},
},
});
export const { setMode, setLogin, setLogout, setFriends, setPosts, setPost } =
authSlice.actions;
export default authSlice.reducer;

Mulund College of Commerce (Autonomous) 2023-24 51


Social Media Web Application

App.js
import {BrowserRouter as Router,Routes,Route, Navigate} from "react-router-dom";
import HomePage from "./scenes/homePage";
import LoginPage from "./scenes/loginPage";
import ProfilePage from "./scenes/profilePage";
import { useMemo } from "react";
import { useSelector } from "react-redux/es/hooks/useSelector";
import { CssBaseline,ThemeProvider} from "@mui/material";
import { createTheme } from "@mui/material/styles";
import { themeSettings } from "./theme";

function App() {
const mode = useSelector((state) => state.mode);
const theme = useMemo(() => createTheme(themeSettings(mode)),[mode]);
const isAuth = Boolean(useSelector((state) => state.token))

return (
<div className="app">
<Router>
<ThemeProvider theme={theme}>
<CssBaseline />
<Routes>
<Route path="/" element={<LoginPage />} />
<Route
path="/home"
element={isAuth ? <HomePage /> : <Navigate to="/" />}
/>
<Route
path="/profile/:userId"
element={isAuth ? <ProfilePage /> : <Navigate to="/" />}
/>
</Routes>
</ThemeProvider>
</Router>
</div>
);
}
export default App;

index.css

Mulund College of Commerce (Autonomous) 2023-24 52


Social Media Web Application

@import
url('https://fonts.googleapis.com/css2?family=Ysabeau+SC:wght@200;500;700&display=sw
ap');
html,
body,
#root,
.app{
height: 100%;
width: 100%;
font-family: "Ysabeau SC", sans-serif;
}

Index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import authReducer from "./state";
import App from './App';
import { configureStore} from '@reduxjs/toolkit';
import { Provider } from 'react-redux';
import {
persistStore,persistReducer,FLUSH,REHYDRATE,PAUSE,PERSIST,PURGE,REGISTER
} from "redux-persist";
import storage from 'redux-persist/lib/storage';
import { PersistGate } from 'redux-persist/integration/react';

const persistConfig = {key:"root",storage,version:1};


const persistedReducer = persistReducer(persistConfig,authReducer);
const store = configureStore({
reducer: persistedReducer,
middleware:(getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck:{
ignoredActions: [FLUSH,REHYDRATE,PAUSE,PERSIST,PURGE,REGISTER],
},
}),
});

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(
<React.StrictMode>
<Provider store={store}>
<PersistGate loading={null} persistor={persistStore(store)}>
<App/>

Mulund College of Commerce (Autonomous) 2023-24 53


Social Media Web Application

</PersistGate>
</Provider>
</React.StrictMode>
);

Theme.js
// color design tokens export
export const colorTokens = {
grey: {
0: "#FFFFFF",
10: "#F6F6F6",
50: "#F0F0F0",
100: "#E0E0E0",
200: "#C2C2C2",
300: "#A3A3A3",
400: "#858585",
500: "#666666",
600: "#4D4D4D",
700: "#333333",
800: "#1A1A1A",
900: "#0A0A0A",
1000: "#000000",
},
primary: {
50: "#E6FBFF",
100: "#CCF7FE",
200: "#99EEFD",
300: "#66E6FC",
400: "#33DDFB",
500: "#00D5FA",
600: "#00A0BC",
700: "#006B7D",
800: "#00353F",
900: "#001519",
},
};

// mui theme settings


export const themeSettings = (mode) => {
return {
palette: {
mode: mode,
...(mode === "dark"
?{

Mulund College of Commerce (Autonomous) 2023-24 54


Social Media Web Application

// palette values for dark mode


primary: {
dark: colorTokens.primary[200],
main: colorTokens.primary[500],
light: colorTokens.primary[800],
},
neutral: {
dark: colorTokens.grey[100],
main: colorTokens.grey[200],
mediumMain: colorTokens.grey[300],
medium: colorTokens.grey[400],
light: colorTokens.grey[700],
},
background: {
default: colorTokens.grey[900],
alt: colorTokens.grey[800],
},
}
:{
// palette values for light mode
primary: {
dark: colorTokens.primary[700],
main: colorTokens.primary[500],
light: colorTokens.primary[100],
},
neutral: {
dark: colorTokens.grey[700],
main: colorTokens.grey[500],
mediumMain: colorTokens.grey[400],
medium: colorTokens.grey[300],
light: colorTokens.grey[50],
},
background: {
default: colorTokens.grey[10],
alt: colorTokens.grey[0],
},
}),
},
typography: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 12,
h1: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 40,

Mulund College of Commerce (Autonomous) 2023-24 55


Social Media Web Application

},
h2: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 32,
},
h3: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 24,
},
h4: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 20,
},
h5: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 16,
},
h6: {
fontFamily: ["Ysabeau SC", "sans-serif"].join(","),
fontSize: 14,
},
},
};
};

Mulund College of Commerce (Autonomous) 2023-24 56


Social Media Web Application

Server
Controllers → auth.js
import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import User from "../models/User.js";

export const register = async(req,res) => {


try{
const{
firstName,
lastName,
email,
password,
picturePath,
friends,
location,
occupation
} = req.body;

const salt = await bcrypt.genSalt();


const passwordHash = await bcrypt.hash(password,salt);

const newUser = new User({


firstName,
lastName,
email,
password : passwordHash,
picturePath,
friends,
location,
occupation,
viewedProfile: Math.floor(Math.random() * 1000),
impressions: Math.floor(Math.random() * 20000),
});
const savedUser = await newUser.save();
res.status(201).json(savedUser); //status code 201 means somethings created
}
catch(error){
res.status(500).json({error:err.message});
}
};

// Logging in
export const login = async(req,res) => {

Mulund College of Commerce (Autonomous) 2023-24 57


Social Media Web Application

try{
const { email,password} = req.body;
const user = await User.findOne({email:email});
if(!user) return (
//toast("User does not exist"),
res.status(400).json({msg: "USer does not exist. "}));

const isMatch = await bcrypt.compare(password,user.password);


if(!isMatch) return res.status(400).json({msg:"Invalid Credentials. "});

const token = jwt.sign({id:user._id},process.env.JWT_SECRET);


delete user.password; // deleting the password so we dont send the password to the
frontend
res.status(200).json({token,user})
}
catch (err) {
//toast("Something went wrong Try Again!"),
res.status(500).json({ error: err.message });
}
};

Controllers → posts.js
import Post from "../models/Post.js";
import User from "../models/User.js";

/* CREATE */
export const createPost = async (req, res) => {
try {
const { userId, description, picturePath } = req.body;
const user = await User.findById(userId);
const newPost = new Post({
userId,
firstName: user.firstName,
lastName: user.lastName,
location: user.location,
description,
userPicturePath: user.picturePath,
picturePath,
likes: {},
comments: [],
});
await newPost.save();

const post = await Post.find();

Mulund College of Commerce (Autonomous) 2023-24 58


Social Media Web Application

res.status(201).json(post);
} catch (err) {
res.status(409).json({ message: err.message });
}
};

/* READ */
export const getFeedPosts = async (req, res) => {
try {
const post = await Post.find();
res.status(200).json(post);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

export const getUserPosts = async (req, res) => {


try {
const { userId } = req.params;
const post = await Post.find({ userId });
res.status(200).json(post);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

/* UPDATE */
export const likePost = async (req, res) => {
try {
const { id } = req.params;
const { userId } = req.body;
const post = await Post.findById(id);
const isLiked = post.likes.get(userId);

if (isLiked) {
post.likes.delete(userId);
} else {
post.likes.set(userId, true);
}

const updatedPost = await Post.findByIdAndUpdate(


id,
{ likes: post.likes },
{ new: true }

Mulund College of Commerce (Autonomous) 2023-24 59


Social Media Web Application

);

res.status(200).json(updatedPost);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

/* CREATE COMMENT */
export const createComment = async (req, res) => {
try {
const { id, userId, comment } = req.body;
const post = await Post.findById(id);

if (!post) {
return res.status(404).json({ message: "Post not found" });
}

const newComment = {
userId,
comment,
};
post.comments.push(newComment);

await post.save();
console.log("id:",id);
console.log("userId:", userId);
console.log("comment:", comment);

const updatedPost = await Post.findByIdAndUpdate(


id,
{ $push: { comments: commentObject } }, // query to insert
{ new: true }
);

res.status(201).json(updatedPost);
return commentObject
} catch (err) {
res.status(500).json({ message: err.message });
}
};

Controllers → users.js
import User from "../models/User.js";

Mulund College of Commerce (Autonomous) 2023-24 60


Social Media Web Application

/* READ */
export const getUser = async (req, res) => {
try {
const { id } = req.params;
const user = await User.findById(id);
res.status(200).json(user);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

export const getUserFriends = async (req, res) => {


try {
const { id } = req.params;
const user = await User.findById(id);

const friends = await Promise.all(


user.friends.map((id) => User.findById(id))
);
const formattedFriends = friends.map(
({ _id, firstName, lastName, occupation, location, picturePath }) => {
return { _id, firstName, lastName, occupation, location, picturePath };
}
);
res.status(200).json(formattedFriends);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

/* UPDATE */
export const addRemoveFriend = async (req, res) => {
try {
const { id, friendId } = req.params;
const user = await User.findById(id);
const friend = await User.findById(friendId);

if (user.friends.includes(friendId)) {
user.friends = user.friends.filter((id) => id !== friendId);
friend.friends = friend.friends.filter((id) => id !== id);
} else {
user.friends.push(friendId);
friend.friends.push(id);

Mulund College of Commerce (Autonomous) 2023-24 61


Social Media Web Application

}
await user.save();
await friend.save();

const friends = await Promise.all(


user.friends.map((id) => User.findById(id))
);
const formattedFriends = friends.map(
({ _id, firstName, lastName, occupation, location, picturePath }) => {
return { _id, firstName, lastName, occupation, location, picturePath };
}
);

res.status(200).json(formattedFriends);
} catch (err) {
res.status(404).json({ message: err.message });
}
};

Middleware → auth.js
import jwt from "jsonwebtoken";

export const verifyToken = async (req, res, next) => {


try {
let token = req.header("Authorization");

if (!token) {
return res.status(403).send("Access Denied");
}

if (token.startsWith("Bearer ")) {
token = token.slice(7, token.length).trimLeft();
}

const verified = jwt.verify(token, process.env.JWT_SECRET);


req.user = verified;
next();
} catch (err) {
res.status(500).json({ error: err.message });
}
};
Models → Post.js
import mongoose from "mongoose";

Mulund College of Commerce (Autonomous) 2023-24 62


Social Media Web Application

const postSchema = mongoose.Schema(


{
userId: {
type: String,
required: true,
},
firstName: {
type: String,
required: true,
},
lastName: {
type: String,
required: true,
},
location: String,
description: String,
picturePath: String,
userPicturePath: String,
likes: {
type: Map,
of: Boolean,
},
comments: {
type: Array,
default: [],
},
},
{ timestamps: true }
);

const Post = mongoose.model("Post", postSchema);

export default Post;

Models → User.js
import mongoose from "mongoose";

const UserSchema = new mongoose.Schema(


{
firstName: {
type: String,
required: true,
min: 2,
max: 50,

Mulund College of Commerce (Autonomous) 2023-24 63


Social Media Web Application

},
lastName: {
type: String,
required: true,
min: 2,
max: 50,
},
email: {
type: String,
required: true,
max: 50,
unique: true,
},
password: {
type: String,
required: true,
min: 5,
},
picturePath: {
type: String,
default: "",
},
friends: {
type: Array,
default: [],
},
location: String,
occupation: String,
viewedProfile: Number,
impressions: Number,
},
{ timestamps: true }
);

const User = mongoose.model("User", UserSchema);


export default User;

routes → auth.js
import express from "express";
import {login} from "../controllers/auth.js";

const router = express.Router();

router.post('/login',login);

Mulund College of Commerce (Autonomous) 2023-24 64


Social Media Web Application

export default router;

routes → posts.js
import express from "express";
import { getFeedPosts, getUserPosts, likePost, createComment } from "../controllers/posts.js";
import { verifyToken } from "../middleware/auth.js";

const router = express.Router();

// READ
router.get("/", verifyToken, getFeedPosts);
router.get("/:userId/posts", verifyToken, getUserPosts);

// UPDATE
router.patch("/:id/like", verifyToken, likePost);
router.post("/:id/comments", verifyToken, createComment);
export default router;

routes → users.js
import express from "express";
import {getUser,getUserFriends,addRemoveFriend} from "../controllers/users.js";
import {verifyToken} from "../middleware/auth.js";

const router = express.Router();

// READ operations
router.get("/:id",verifyToken,getUser);
router.get("/:id/friends",verifyToken,getUserFriends);

// UPDATE operations
router.patch("/:id/:friendId",verifyToken,addRemoveFriend);

export default router;

.env
MONGO_URL =
"mongodb+srv://atharvagholap24:[email protected]/?retryWrites=tr
ue&w=majority"
PORT=3001
JWT_SECRET = "idontunderstandbutiloveyou"

Index.js

Mulund College of Commerce (Autonomous) 2023-24 65


Social Media Web Application

import express from "express";


import bodyParser from "body-parser";
import mongoose from "mongoose";
import cors from "cors";
import dotenv from "dotenv";
import multer from "multer";
import helmet from "helmet";
import morgan from "morgan";
import path from "path";
import { fileURLToPath } from "url";
import authRoutes from "./routes/auth.js";
import userRoutes from "./routes/users.js";
import postRoutes from "./routes/posts.js";
import { register } from "./controllers/auth.js";
import { createPost } from "./controllers/posts.js";
import { verifyToken } from "./middleware/auth.js";
import User from "./models/User.js";
import Post from "./models/Post.js";

/* CONFIGURATIONS */
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
dotenv.config();
const app = express();
app.use(express.json());
app.use(helmet());
app.use(helmet.crossOriginResourcePolicy({ policy: "cross-origin" }));
app.use(morgan("common"));
app.use(bodyParser.json({ limit: "30mb", extended: true }));
app.use(bodyParser.urlencoded({ limit: "30mb", extended: true }));
app.use(cors());
app.use("/assets", express.static(path.join(__dirname, "public/assets")));

/* FILE STORAGE */
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "public/assets");
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
});
const upload = multer({ storage });

Mulund College of Commerce (Autonomous) 2023-24 66


Social Media Web Application

/* ROUTES WITH FILES */


app.post("/auth/register", upload.single("picture"), register);
app.post("/posts", verifyToken, upload.single("picture"), createPost);

/* ROUTES */
app.use("/auth", authRoutes);
app.use("/users", userRoutes);
app.use("/posts", postRoutes);

/* MONGOOSE SETUP */
const PORT = process.env.PORT || 6001;
mongoose
.connect(process.env.MONGO_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(() => {
app.listen(PORT, () => console.log(`Server Port: ${PORT}`));
//User.insertMany(users);
//Post.insertMany(posts);
})
.catch((error) => console.log(`${error} did not connect`));

Mulund College of Commerce (Autonomous) 2023-24 67


Social Media Web Application

6. Results

6.1 Validation and Naming Conventions Event Table 2

Sr.no Field Validation Reason


Name
1 firstname Required Firstname of the user cannot be empty

2 lastname Required Lastname of the user cannot be empty

3 email Required, email Email of the user cannot be empty and its
format should be correct
4 password Required Password of the account cannot be empty

5 location Required Location of the user cannot be empty

6 occupation Required Occupation of the user cannot be empty

7 picture Required, Profile picture of the user cannot be empty


FileInput and should be a file

6.2 Screenshots
6.2.1 Login Page

Figure 12

Mulund College of Commerce (Autonomous) 2023-24 68


Social Media Web Application

6.2.2 Account Registration Page

Figure 13

Mulund College of Commerce (Autonomous) 2023-24 69


Social Media Web Application

6.2.3 Home Page

6.2.4 Profile Page

Figure 15

Figure 14

Mulund College of Commerce (Autonomous) 2023-24 70


Social Media Web Application

6.2.5 NightMode Activated

Figure 16

6.2.6 Post

Figure 17

Mulund College of Commerce (Autonomous) 2023-24 71


Social Media Web Application

6.2.7 Logout

Mulund College of Commerce (Autonomous) 2023-24 72


Social Media Web Application

7. Future Enhancement & Conclusion

7.1 Future Enhancement

• Adding Feature to Post variety of contents like Clips, Audios and any other
files
• Dynamic Advertisement of Sponsors
• Active Feature to Create our own Advertisement
• Searching different users from the search bar
• Active incorporating of post impact and number of visitors
• Receive notifications when running is background
• More detailed comments with extra feature to delete our own comment, edit
it and like others comments
• Able to share a post by generating its url
• Active Feature to edit out profile details

7.2 Conclusions

Wise aims to provide a seamless and user-friendly platform for people from all
around the world to connect, interact, and share content. The core objective of this
application is to foster emotional and professional connections among users while
ensuring simplicity and safety. Unlike other existing social media platforms, this
web app focuses on providing a straightforward and easy-to-use interface,
eliminating unnecessary complexities.

8. References

www.stackoverflow.com

www.react.dev

www.mongodb.com/docs

www.expressjs.com

www.mongodb.com/languages/mern-stack-tutorial

www.react-redux.com

Mulund College of Commerce (Autonomous) 2023-24 73


Social Media Web Application

9. Annexures

9.1 Figures List

Class Diagram ............................................................................................................................ 6


Use Case Diagram...................................................................................................................... 7
Sequence Diagram ..................................................................................................................... 8
Activity Diagram ....................................................................................................................... 9
State Diagram........................................................................................................................... 10
Package Diagram ..................................................................................................................... 10
Component Diagram ................................................................................................................ 11
Deployment Diagram ............................................................................................................... 11
Database: test ........................................................................................................................... 12
Collection: post ........................................................................................................................ 12
Collection: user ........................................................................................................................ 13
Login page ............................................................................................................................... 68
Registration page ..................................................................................................................... 69
Homepage ................................................................................................................................ 70
Profile page .............................................................................................................................. 70
Nightmode Activated ............................................................................................................... 71
Post .......................................................................................................................................... 71

9.2 Table List

Event Table ............................................................................................................................... 5


Validation and Naming Conventions ....................................................................................... 68

Mulund College of Commerce (Autonomous) 2023-24 74

You might also like