From 2cd31b7601f34e76b2d0b2e7cb92dd3cd1960ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20K=C5=82osi=C5=84ski?= Date: Sun, 22 Dec 2024 00:10:55 +0100 Subject: [PATCH 1/3] feature: Connect posts fully with backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adjust posts adresses for new structure, - Correct basic info user, - Connect editing and deleting of posts. Refs: 869768m7p Signed-off-by: Patryk Kłosiński --- .../src/Features/CreatePost/CreatePost.tsx | 2 +- frontend/src/Features/MainPage/MainPage.tsx | 47 ++++++++++--------- frontend/src/Features/MainPage/types/Post.tsx | 17 +++++-- .../Root/components/Navbar/Navbar.tsx | 2 +- .../shared/components/Cards/Post/Post.tsx | 27 +++-------- .../Post/components/EditPost/EditPost.tsx | 4 +- .../Post/components/MenuPost/MenuPost.tsx | 5 +- .../Post/components/RemovePost/RemovePost.tsx | 4 +- 8 files changed, 55 insertions(+), 53 deletions(-) diff --git a/frontend/src/Features/CreatePost/CreatePost.tsx b/frontend/src/Features/CreatePost/CreatePost.tsx index 93b098c..a53be59 100644 --- a/frontend/src/Features/CreatePost/CreatePost.tsx +++ b/frontend/src/Features/CreatePost/CreatePost.tsx @@ -24,7 +24,7 @@ export const CreatePost = () => { return; } - api.post('/api/posts/create', null, {params: {content: contentToSave}}).then((response) => { + api.post('/api/posts', null, {params: {content: contentToSave}}).then((response) => { if (response.status === 200) { close(); } diff --git a/frontend/src/Features/MainPage/MainPage.tsx b/frontend/src/Features/MainPage/MainPage.tsx index 01acfa9..88217fc 100644 --- a/frontend/src/Features/MainPage/MainPage.tsx +++ b/frontend/src/Features/MainPage/MainPage.tsx @@ -5,30 +5,35 @@ import {Post} from "../shared/components/Cards/Post"; import {PostDTO} from "./types/Post.tsx"; export const MainPage = () => { - - const [posts, setPosts] = useState([]); + const [posts, setPosts] = useState([]); useEffect(() => { - api.get("/api/posts/get-all").then((response) => { - setPosts(response.data); + api.get<{ content: PostDTO[] }>("/api/posts").then((response) => { + setPosts(response.data.content); }); }, []); - return ( - - Main page + return ( + + Main page - {/*Posts*/} - {posts.map((post) => ( - { - return "https://picsum.photos/seed/" + Math.random() + "/800/2200"; - }) - } - /> - ))} - - ) -} \ No newline at end of file + {/* Post rendering */} + {posts.map((post) => ( + { + return "https://picsum.photos/seed/" + Math.random() + "/800/2200"; + }) + } + /> + ))} + + ); +}; diff --git a/frontend/src/Features/MainPage/types/Post.tsx b/frontend/src/Features/MainPage/types/Post.tsx index ff2fa61..fbf1870 100644 --- a/frontend/src/Features/MainPage/types/Post.tsx +++ b/frontend/src/Features/MainPage/types/Post.tsx @@ -1,5 +1,14 @@ export type PostDTO = { - content: string; - ownerLogin: string; - createdAt: string; -} \ No newline at end of file + id: string, + content: string, + createdAt: string, + numberOfComments: number, + author: { + id: string; + name: string; + surname: string; + login: string; + profilePicture: string | null; + }, + photosUrls?: string[] +}; diff --git a/frontend/src/Features/Root/components/Navbar/Navbar.tsx b/frontend/src/Features/Root/components/Navbar/Navbar.tsx index 7b764c3..a494f10 100644 --- a/frontend/src/Features/Root/components/Navbar/Navbar.tsx +++ b/frontend/src/Features/Root/components/Navbar/Navbar.tsx @@ -31,7 +31,7 @@ export const Navbar = () => { useEffect(() => { if (auth.user) { - api.get('/api/users/get-basic-user-info', {params: {login: auth.user.login}}).then((response) => { + api.get('/api/users/basic-user-info', {params: {login: auth.user.login}}).then((response) => { setBasicUserInfo(response.data); }); } diff --git a/frontend/src/Features/shared/components/Cards/Post/Post.tsx b/frontend/src/Features/shared/components/Cards/Post/Post.tsx index 4f387f9..d6b6eda 100644 --- a/frontend/src/Features/shared/components/Cards/Post/Post.tsx +++ b/frontend/src/Features/shared/components/Cards/Post/Post.tsx @@ -1,5 +1,4 @@ import {Avatar, BackgroundImage, Box, Button, Card, Divider, Group, SimpleGrid, Stack, Text} from "@mantine/core"; -import {User} from "../../../types/User.tsx"; import {InnerHtmlHandler} from "../../InnerHtmlHandler"; import {DateFormatter} from "../../../utils/DateFormatter.tsx"; import {IconMessage, IconPaw, IconShare3} from "@tabler/icons-react"; @@ -7,18 +6,12 @@ import {useAuthStore} from "../../../services/authStore.ts"; import {useNavigate} from "react-router-dom"; import {ImageWithSkeleton} from "../../ImageWithSkeleton"; import {MenuPost} from "./components/MenuPost"; +import {PostDTO} from "../../../../MainPage/types/Post.tsx"; -type PostProps = { - ownerLogin: string; - contentHtml: string; - photosUrls?: string[]; - createdAt: string; -} - -export const Post = (props: PostProps) => { +export const Post = (props: PostDTO) => { const auth = useAuthStore(); - const isOwner = auth.user?.login === props.ownerLogin; + const isOwner = auth.user?.login === props.author.login; const navigate = useNavigate(); /*Render this element each time when number of photos will change*/ @@ -118,29 +111,23 @@ export const Post = (props: PostProps) => { ); }; - const user = { - name: "John", - surname: "Doe", - login: "johndoe", - } as User; - return ( - navigate(`/profile/${auth.user?.tag}`)} style={{cursor: "pointer"}}> + navigate(`/profile/@${props.author.login}`)} style={{cursor: "pointer"}}> - {user.name} {user.surname} + {props.author.name} {props.author.surname} {DateFormatter(props.createdAt)} {isOwner && - + } - + {/*// Show photos if they exist*/} {props.photosUrls && props.photosUrls.length > 0 && ( diff --git a/frontend/src/Features/shared/components/Cards/Post/components/EditPost/EditPost.tsx b/frontend/src/Features/shared/components/Cards/Post/components/EditPost/EditPost.tsx index d420c91..4241ee3 100644 --- a/frontend/src/Features/shared/components/Cards/Post/components/EditPost/EditPost.tsx +++ b/frontend/src/Features/shared/components/Cards/Post/components/EditPost/EditPost.tsx @@ -3,6 +3,7 @@ import {IconPencil} from "@tabler/icons-react"; import {Menu, rem} from "@mantine/core"; import {useRef, useState} from "react"; import {ModalRichContent} from "../../../../../consts"; +import api from "../../../../../services/api.ts"; type EditPostProps = { content?: string; @@ -20,8 +21,7 @@ export const EditPost = (props: EditPostProps) => { } const handleEditPost = () => { - // TODO: Replace with actual edit logic - console.log('Edit post: ', contentRef.current); + api.put(`/api/posts/${props.postId}`, null, {params: {content: contentRef.current}}); }; return ( diff --git a/frontend/src/Features/shared/components/Cards/Post/components/MenuPost/MenuPost.tsx b/frontend/src/Features/shared/components/Cards/Post/components/MenuPost/MenuPost.tsx index e75611c..adb28b2 100644 --- a/frontend/src/Features/shared/components/Cards/Post/components/MenuPost/MenuPost.tsx +++ b/frontend/src/Features/shared/components/Cards/Post/components/MenuPost/MenuPost.tsx @@ -4,6 +4,7 @@ import {EditPost} from "../EditPost"; import {RemovePost} from "../RemovePost"; type MenuPostProps = { + postId?: string; content?: string; } @@ -17,8 +18,8 @@ export const MenuPost = (props: MenuPostProps) => { Manage - - + + ); diff --git a/frontend/src/Features/shared/components/Cards/Post/components/RemovePost/RemovePost.tsx b/frontend/src/Features/shared/components/Cards/Post/components/RemovePost/RemovePost.tsx index 691f13f..51a33ab 100644 --- a/frontend/src/Features/shared/components/Cards/Post/components/RemovePost/RemovePost.tsx +++ b/frontend/src/Features/shared/components/Cards/Post/components/RemovePost/RemovePost.tsx @@ -1,6 +1,7 @@ import {Menu, rem, Text} from "@mantine/core"; import {IconTrash} from "@tabler/icons-react"; import {ModificationModal} from "../../../../ModificationModal"; +import api from "../../../../../services/api.ts"; type RemovePostProps = { postId?: string; @@ -8,8 +9,7 @@ type RemovePostProps = { export const RemovePost = (props: RemovePostProps) => { const handleRemoval = () => { - // TODO: Replace with actual removal logic - console.log('Remove post: ', props.postId); + api.delete(`/api/posts/${props.postId}`); }; return ( From f4f62755485550da4b365f47790517c8d02de13d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20K=C5=82osi=C5=84ski?= Date: Sun, 22 Dec 2024 01:04:14 +0100 Subject: [PATCH 2/3] feature: Connect posts fully with backend MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Small enhancements: - Add infinite scroll - Add visible number of comments Refs: 869768m7p Signed-off-by: Patryk Kłosiński --- frontend/src/Features/MainPage/MainPage.tsx | 38 ++------- .../InfiniteScroll/InfiniteScroll.tsx | 80 +++++++++++++++++++ .../components/InfiniteScroll/index.tsx | 1 + .../shared/components/Cards/Post/Post.tsx | 21 ++++- 4 files changed, 106 insertions(+), 34 deletions(-) create mode 100644 frontend/src/Features/MainPage/components/InfiniteScroll/InfiniteScroll.tsx create mode 100644 frontend/src/Features/MainPage/components/InfiniteScroll/index.tsx diff --git a/frontend/src/Features/MainPage/MainPage.tsx b/frontend/src/Features/MainPage/MainPage.tsx index 88217fc..a759649 100644 --- a/frontend/src/Features/MainPage/MainPage.tsx +++ b/frontend/src/Features/MainPage/MainPage.tsx @@ -1,39 +1,13 @@ -import {Box, Title} from "@mantine/core"; -import {useEffect, useState} from "react"; -import api from "../shared/services/api.ts"; -import {Post} from "../shared/components/Cards/Post"; -import {PostDTO} from "./types/Post.tsx"; +import {Box, Center} from "@mantine/core"; +import {InfiniteScroll} from "./components/InfiniteScroll"; export const MainPage = () => { - const [posts, setPosts] = useState([]); - - useEffect(() => { - api.get<{ content: PostDTO[] }>("/api/posts").then((response) => { - setPosts(response.data.content); - }); - }, []); - return ( - Main page - - {/* Post rendering */} - {posts.map((post) => ( - { - return "https://picsum.photos/seed/" + Math.random() + "/800/2200"; - }) - } - /> - ))} +
+ {/* Post rendering */} + +
); }; diff --git a/frontend/src/Features/MainPage/components/InfiniteScroll/InfiniteScroll.tsx b/frontend/src/Features/MainPage/components/InfiniteScroll/InfiniteScroll.tsx new file mode 100644 index 0000000..7ec709c --- /dev/null +++ b/frontend/src/Features/MainPage/components/InfiniteScroll/InfiniteScroll.tsx @@ -0,0 +1,80 @@ +import {useCallback, useEffect, useState} from "react"; +import api from "../../../shared/services/api.ts"; +import {Group, Loader, ScrollArea, Text} from "@mantine/core"; +import {Post} from "../../../shared/components/Cards/Post"; +import {PostDTO} from "../../types/Post.tsx"; + +export const InfiniteScroll = () => { + const [posts, setPosts] = useState([]); + const [loading, setLoading] = useState(false); + const [hasMore, setHasMore] = useState(true); + const [page, setPage] = useState(0); + + const loadPosts = useCallback(async () => { + if (loading || !hasMore) return; + + setLoading(true); + + try { + const response = await api.get(`/api/posts`, { + params: {pageNo: page, pageSize: 10}, + }); + + const newPosts = response.data.content; + + setPosts((prevPosts) => [...prevPosts, ...newPosts]); + setHasMore(response.data.totalPages > page + 1); + setPage((prevPage) => prevPage + 1); + } catch (error) { + console.error('Error loading posts:', error); + } finally { + setLoading(false); + } + }, [loading, hasMore, page]); + + useEffect(() => { + loadPosts(); + }, [loadPosts]); + + // Funkcja do obsługi scrolla + const handleScroll = (event: { currentTarget: any; }) => { + const target = event.currentTarget; + if (target.scrollHeight - target.scrollTop <= target.clientHeight + 10) { + loadPosts(); + } + }; + + return ( + + {posts.map((post) => ( + { + return "https://picsum.photos/seed/" + Math.random() + "/800/2200"; + }) + } + /> + ))} + {loading && ( + + + + )} + {!hasMore && !loading && ( + + No more posts to load + + )} + + ); +} \ No newline at end of file diff --git a/frontend/src/Features/MainPage/components/InfiniteScroll/index.tsx b/frontend/src/Features/MainPage/components/InfiniteScroll/index.tsx new file mode 100644 index 0000000..978a52c --- /dev/null +++ b/frontend/src/Features/MainPage/components/InfiniteScroll/index.tsx @@ -0,0 +1 @@ +export {InfiniteScroll} from './InfiniteScroll'; \ No newline at end of file diff --git a/frontend/src/Features/shared/components/Cards/Post/Post.tsx b/frontend/src/Features/shared/components/Cards/Post/Post.tsx index d6b6eda..58cdee3 100644 --- a/frontend/src/Features/shared/components/Cards/Post/Post.tsx +++ b/frontend/src/Features/shared/components/Cards/Post/Post.tsx @@ -1,4 +1,16 @@ -import {Avatar, BackgroundImage, Box, Button, Card, Divider, Group, SimpleGrid, Stack, Text} from "@mantine/core"; +import { + Avatar, + BackgroundImage, + Badge, + Box, + Button, + Card, + Divider, + Group, + SimpleGrid, + Stack, + Text +} from "@mantine/core"; import {InnerHtmlHandler} from "../../InnerHtmlHandler"; import {DateFormatter} from "../../../utils/DateFormatter.tsx"; import {IconMessage, IconPaw, IconShare3} from "@tabler/icons-react"; @@ -142,7 +154,12 @@ export const Post = (props: PostDTO) => { -