From 929aa09d58786ac7ffa178c1a072871a82ddf6c6 Mon Sep 17 00:00:00 2001 From: DmytroHoncharuk Date: Mon, 13 Jan 2025 19:48:15 +0200 Subject: [PATCH 1/4] almost done --- src/App.tsx | 138 +++++++++++++++++------- src/components/PostDetails.tsx | 185 ++++++++++++++++---------------- src/components/PostsList.tsx | 138 +++++++++++------------- src/components/UserSelector.tsx | 54 ++++++---- src/utils/api.ts | 16 +++ 5 files changed, 304 insertions(+), 227 deletions(-) create mode 100644 src/utils/api.ts diff --git a/src/App.tsx b/src/App.tsx index 017957182..012d580fd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,57 +4,117 @@ import 'bulma/css/bulma.css'; import '@fortawesome/fontawesome-free/css/all.css'; import './App.scss'; -import { PostsList } from './components/PostsList'; -import { PostDetails } from './components/PostDetails'; import { UserSelector } from './components/UserSelector'; +import React, { useEffect } from 'react'; +import { User } from './types/User'; +import { getPostsOfUser, getUsers } from './utils/api'; +import { Post } from './types/Post'; +import { PostsList } from './components/PostsList'; import { Loader } from './components/Loader'; +import { PostDetails } from './components/PostDetails'; -export const App = () => ( -
-
-
-
-
-
- -
+export const App = () => { + const [usersFromServer, setUsersFromServer] = React.useState(); + const [postsFromServer, setPostsFromServer] = React.useState(); -
-

No user selected

+ const [chosenUser, setChosenUser] = React.useState(null); + const [userError, setUserError] = React.useState(false); + const [postError, setPostError] = React.useState(false); + const [isPostsLoading, setIsPostsLoading] = React.useState(false); + const [activePost, setActivePost] = React.useState(null); - + useEffect(() => { + const fetchUsers = async () => { + try { + const currentUsers = await getUsers(); -
- Something went wrong! -
+ setUsersFromServer(currentUsers); + } catch (err) { + setUserError(true); + } finally { + } + }; + + fetchUsers(); + }, []); -
- No posts yet + useEffect(() => { + const fetchPosts = async () => { + setIsPostsLoading(true); + try { + const currentPosts = await getPostsOfUser(chosenUser?.id ?? 0); + + setPostsFromServer(currentPosts); + } catch (err) { + setPostError(true); + } finally { + setIsPostsLoading(false); + } + }; + + if (chosenUser) { + setActivePost(null); + fetchPosts(); + } + }, [chosenUser]); + + return ( +
+
+
+
+
+
+
- +
+ {!chosenUser ? ( +

No user selected

+ ) : isPostsLoading ? ( + + ) : postError ? ( +
+ Something went wrong! +
+ ) : postsFromServer?.length === 0 ? ( +
+ No posts yet +
+ ) : ( + + )} +
-
-
-
- +
+
+ +
-
-
-); +
+ ); +}; diff --git a/src/components/PostDetails.tsx b/src/components/PostDetails.tsx index 2f82db916..d91c430ab 100644 --- a/src/components/PostDetails.tsx +++ b/src/components/PostDetails.tsx @@ -1,107 +1,106 @@ -import React from 'react'; +import { getCommentsOfPost } from '../utils/api'; +import React, { useEffect } from 'react'; +import { Post } from '../types/Post'; +import { Comment } from '../types/Comment'; import { Loader } from './Loader'; -import { NewCommentForm } from './NewCommentForm'; -export const PostDetails: React.FC = () => { - return ( -
-
-
-

- #18: voluptate et itaque vero tempora molestiae -

- -

- eveniet quo quis laborum totam consequatur non dolor ut et est - repudiandae est voluptatem vel debitis et magnam -

-
- -
- - -
- Something went wrong -
+type Props = { + post?: Post | null; +}; -

- No comments yet -

+export const PostDetails: React.FC = ({ post }) => { + const [isLoading, setIsLoading] = React.useState(false); + const [error, setError] = React.useState(false); + const [commentsFromServer, setCommentsFromServer] = React.useState( + [], + ); -

Comments:

+ useEffect(() => { + const fetchComments = async () => { + setIsLoading(true); -
-
- - Misha Hrynko - - -
+ try { + const currentComments = await getCommentsOfPost(post?.id ?? 0); -
- Some comment -
-
+ setCommentsFromServer(currentComments); + } catch (err) { + setError(true); + } finally { + setIsLoading(false); + } + }; -
-
- - Misha Hrynko - + if (post?.id) { + fetchComments(); + } + }, [post?.id]); - -
-
- One more comment -
-
- -
-
- - Misha Hrynko - + return ( +
+
+

{`#${post?.id}: ${post?.title}`}

+

{post?.body}

+
- + + ) : ( + <> +

Comments:

+ {commentsFromServer.map(comment => ( +
- delete button - -
- -
- {'Multi\nline\ncomment'} -
-
- - -
- - +
+ + {comment.name} + + +
+
+ {comment.body} +
+ + ))} + + + )}
+ + {/**/}
); }; diff --git a/src/components/PostsList.tsx b/src/components/PostsList.tsx index cf90f04b0..25817fb8a 100644 --- a/src/components/PostsList.tsx +++ b/src/components/PostsList.tsx @@ -1,86 +1,70 @@ import React from 'react'; +import { Post } from '../types/Post'; +import classNames from 'classnames'; +type Props = { + posts?: Post[]; + activePost: Post | null; + choosePost: React.Dispatch>; +}; -export const PostsList: React.FC = () => ( -
-

Posts:

+export const PostsList: React.FC = ({ + posts, + activePost, + choosePost, +}) => { + function handleClickToChoosePost(post: Post) { + if (!activePost) { + choosePost(post); + } - - - - - - {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */} - - - + if (activePost?.id === post.id) { + choosePost(null); + } - - - + if (activePost?.id !== post.id) { + choosePost(post); + } + } - + return ( +
+

Posts:

-
- +
#Title
17 - fugit voluptas sed molestias voluptatem provident - - -
+ + + + + {/* eslint-disable-next-line jsx-a11y/control-has-associated-label */} + + + - - + + {posts?.map(post => ( + + - + - - - - - - - - - - - - - - - - - -
#Title
18
{post.id} - voluptate et itaque vero tempora molestiae - {post.title} - -
19adipisci placeat illum aut reiciendis qui - -
20doloribus ad provident suscipit at - -
-
-); + + + + + ))} + + + + ); +}; diff --git a/src/components/UserSelector.tsx b/src/components/UserSelector.tsx index c89442841..68411cdd3 100644 --- a/src/components/UserSelector.tsx +++ b/src/components/UserSelector.tsx @@ -1,16 +1,34 @@ import React from 'react'; +import { User } from '../types/User'; +import classNames from 'classnames'; + +type Props = { + users: User[] | null; + chosenUser: User | null; + chooseUser: React.Dispatch>; +}; + +export const UserSelector: React.FC = ({ + users, + chosenUser, + chooseUser, +}) => { + const [isActive, setIsActive] = React.useState(false); -export const UserSelector: React.FC = () => { return ( -
+