Content of home page

This commit is contained in:
Andrew Trieu
2023-07-21 23:47:11 +03:00
parent 958a841ad8
commit 47381ee629
5 changed files with 259 additions and 0 deletions

View File

@@ -21,3 +21,4 @@ Table:
| 16.07.2023 | Fix mock schema and move mock injections out of index.js | 1 |
| 18.07.2023 | Home page and navigate to login/register page if not logged in | 20 |
| 19.07.2023 | Post widget | 10 |
| 21.07.2023 | Each post on home page | 20 |

View File

@@ -0,0 +1,77 @@
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 ProfilePhoto from "./ProfilePhoto";
const Friend = ({ friendId, userName, subtitle, profilePicturePath }) => {
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 isFriend = friends.find((friend) => friend._id === friendId);
const handleFriend = async () => {
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 }));
};
return (
<FlexBetween>
<FlexBetween gap="1rem">
<ProfilePhoto image={profilePicturePath} size="55px" />
<Box
onClick={() => {
navigate(`/profile/${friendId}`);
navigate(0);
}}
>
<Typography
color={main}
variant="h5"
fontWeight="500"
sx={{
"&:hover": { color: palette.primary.light, cursor: "pointer" },
}}
>
{userName}
</Typography>
<Typography color={medium} fontSize="0.75rem">
{subtitle}
</Typography>
</Box>
</FlexBetween>
<IconButton
onClick={() => handleFriend()}
sx={{ backgroundColor: primaryLight, p: "0.6rem" }}
>
{isFriend ? (
<PersonRemoveOutlined sx={{ color: primaryDark }} />
) : (
<PersonAddOutlined sx={{ color: primaryDark }} />
)}
</IconButton>
</FlexBetween>
);
};
export default Friend;

View File

@@ -3,6 +3,7 @@ import { useSelector } from "react-redux";
import Navbar from "scenes/navbar";
import UserWidget from "scenes/widgets/UserWidget";
import PostWidget from "scenes/widgets/PostWidget";
import FeedWidget from "scenes/widgets/FeedWidget";
const HomePage = () => {
const isNotMobile = useMediaQuery("(min-width: 1000px)");
@@ -26,6 +27,7 @@ const HomePage = () => {
mt={isNotMobile ? undefined : "2rem"}
>
<PostWidget profilePicturePath={profilePicturePath} />
<FeedWidget userId={_id} />
</Box>
{isNotMobile && <Box flexBasis="26%"></Box>}
</Box>

View File

@@ -0,0 +1,109 @@
import {
ChatBubbleOutlineOutlined,
FavoriteBorderOutlined,
FavoriteOutlined,
ShareOutlined,
} from "@mui/icons-material";
import { Box, Divider, Typography, IconButton, useTheme } from "@mui/material";
import FlexBetween from "components/FlexBetween";
import Friend from "components/FriendList";
import WidgetWrapper from "components/WidgetWrapper";
import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setPosts } from "state";
const ContentWidget = ({
postId,
userId,
userName,
location,
content,
profilePicturePath,
contentPicturePath,
likes,
comments,
}) => {
const [isComments, setIsComments] = useState(false);
const dispatch = useDispatch();
const token = useSelector((state) => state.token);
const loggedInUserId = useSelector((state) => state.user._id);
const isLiked = Boolean(likes[loggedInUserId]);
const likesCount = Object.keys(likes).length;
const { palette } = useTheme();
const primary = palette.primary.main;
const main = palette.neutral.main;
const handleLike = 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(setPosts({ post: updatedPost }));
};
return (
<WidgetWrapper m="2rem 0">
<Friend
friendId={userId}
userName={userName}
subtitle={location}
profilePicturePath={profilePicturePath}
/>
<Typography color={main} sx={{ mt: "1rem" }}>
{content}
</Typography>
{contentPicturePath && (
<img
width="100%"
height="auto"
alt="post"
style={{ borderRadius: "0.75rem", marginTop: "0.75rem" }}
src={`http://localhost:3001/assets/${contentPicturePath}`}
/>
)}
<FlexBetween mt="0.25rem">
<FlexBetween gap="1rem">
<FlexBetween gap="0.3rem">
<IconButton onClick={handleLike}>
{isLiked ? (
<FavoriteOutlined sx={{ color: primary }} />
) : (
<FavoriteBorderOutlined />
)}
</IconButton>
<Typography>{likesCount}</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.5rems">
{comments.map((comment, i) => (
<Box key={`${userName}-${i}`}>
<Divider />
<Typography sx={{ color: main, m: "0.5rem 0", pl: "1rem" }}>
{comment}
</Typography>
</Box>
))}
<Divider />
</Box>
)}
</WidgetWrapper>
);
};
export default ContentWidget;

View File

@@ -0,0 +1,70 @@
import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { setPosts } from "state";
import ContentWidget from "./ContentWidget";
const FeedWidget = ({ 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 posts = await response.json();
dispatch(setPosts({ posts }));
};
const getUserPosts = async () => {
const response = await fetch(`http://localhost:3001/posts/${userId}`, {
method: "GET",
headers: {
Authorization: `Bearer ${token}`,
},
});
const posts = await response.json();
dispatch(setPosts({ posts }));
};
useEffect(() => {
isProfile ? getUserPosts() : getPosts();
}, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<>
{posts.map(
({
_id,
userId,
firstName,
lastName,
location,
content,
profilePicturePath,
contentPicturePath,
likes,
comments,
}) => (
<ContentWidget
key={_id}
postId={_id}
userId={userId}
userName={`${firstName} ${lastName}`}
location={location}
content={content}
profilePicturePath={profilePicturePath}
contentPicturePath={contentPicturePath}
likes={likes}
comments={comments}
></ContentWidget>
)
)}
</>
);
};
export default FeedWidget;