diff --git a/README.md b/README.md
index fb9afa2..d9de9ce 100644
--- a/README.md
+++ b/README.md
@@ -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 |
diff --git a/client/src/components/Friend.jsx b/client/src/components/Friend.jsx
new file mode 100644
index 0000000..0d2086d
--- /dev/null
+++ b/client/src/components/Friend.jsx
@@ -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 (
+
+
+
+ {
+ navigate(`/profile/${friendId}`);
+ navigate(0);
+ }}
+ >
+
+ {userName}
+
+
+ {subtitle}
+
+
+
+ handleFriend()}
+ sx={{ backgroundColor: primaryLight, p: "0.6rem" }}
+ >
+ {isFriend ? (
+
+ ) : (
+
+ )}
+
+
+ );
+};
+
+export default Friend;
diff --git a/client/src/scenes/homePage/index.jsx b/client/src/scenes/homePage/index.jsx
index 3289eac..cb83261 100644
--- a/client/src/scenes/homePage/index.jsx
+++ b/client/src/scenes/homePage/index.jsx
@@ -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"}
>
+
{isNotMobile && }
diff --git a/client/src/scenes/widgets/ContentWidget.jsx b/client/src/scenes/widgets/ContentWidget.jsx
new file mode 100644
index 0000000..5bd95ad
--- /dev/null
+++ b/client/src/scenes/widgets/ContentWidget.jsx
@@ -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 (
+
+
+
+ {content}
+
+ {contentPicturePath && (
+
+ )}
+
+
+
+
+ {isLiked ? (
+
+ ) : (
+
+ )}
+
+ {likesCount}
+
+
+ setIsComments(!isComments)}>
+
+
+ {comments.length}
+
+
+
+
+
+
+ {isComments && (
+
+ {comments.map((comment, i) => (
+
+
+
+ {comment}
+
+
+ ))}
+
+
+ )}
+
+ );
+};
+
+export default ContentWidget;
diff --git a/client/src/scenes/widgets/FeedWidget.jsx b/client/src/scenes/widgets/FeedWidget.jsx
new file mode 100644
index 0000000..2aba9c0
--- /dev/null
+++ b/client/src/scenes/widgets/FeedWidget.jsx
@@ -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,
+ }) => (
+
+ )
+ )}
+ >
+ );
+};
+
+export default FeedWidget;