From 274d478056d688272be099f865fa82cac56c6ee6 Mon Sep 17 00:00:00 2001 From: Yuliia Nudyk Date: Wed, 25 Sep 2024 15:40:09 +0300 Subject: [PATCH 1/5] solution --- src/App.tsx | 99 ++++++++------ src/components/CommentItem.tsx | 50 +++++++ src/components/CommentsList.tsx | 30 +++++ src/components/ErrorNotification.tsx | 15 +++ src/components/NewCommentForm.tsx | 146 +++++++++++++++----- src/components/PostDetails.tsx | 190 ++++++++++++++------------- src/components/PostItem.tsx | 36 +++++ src/components/PostsList.tsx | 140 ++++++++------------ src/components/UserPosts.tsx | 66 ++++++++++ src/components/UserSelector.tsx | 72 ++++++---- src/hooks/useOutsideClick.ts | 23 ++++ src/services/comments.ts | 14 ++ src/services/posts.ts | 6 + src/services/users.ts | 6 + 14 files changed, 618 insertions(+), 275 deletions(-) create mode 100644 src/components/CommentItem.tsx create mode 100644 src/components/CommentsList.tsx create mode 100644 src/components/ErrorNotification.tsx create mode 100644 src/components/PostItem.tsx create mode 100644 src/components/UserPosts.tsx create mode 100644 src/hooks/useOutsideClick.ts create mode 100644 src/services/comments.ts create mode 100644 src/services/posts.ts create mode 100644 src/services/users.ts diff --git a/src/App.tsx b/src/App.tsx index 017957182..380768ad0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,60 +1,77 @@ -import classNames from 'classnames'; +// #region imports +import cn from 'classnames'; import 'bulma/css/bulma.css'; import '@fortawesome/fontawesome-free/css/all.css'; import './App.scss'; -import { PostsList } from './components/PostsList'; +import { useEffect, useState } from 'react'; import { PostDetails } from './components/PostDetails'; import { UserSelector } from './components/UserSelector'; -import { Loader } from './components/Loader'; - -export const App = () => ( -
-
-
-
-
-
- -
+import { UserPosts } from './components/UserPosts'; +import { getUsers } from './services/users'; +import { Post } from './types/Post'; +import { User } from './types/User'; +// #endregion -
-

No user selected

+export const App = () => { + // #region states + const [users, setUsers] = useState([]); + const [selectedUserId, setSelectedUserId] = useState(null); + const [selectedPost, setSelectedPost] = useState(null); + // #endregion - + useEffect(() => { + getUsers().then(setUsers); + }, []); -
- Something went wrong! + return ( +
+
+
+
+
+
+
-
- No posts yet -
+
+ {!selectedUserId && ( +

No user selected

+ )} - + {selectedUserId && ( + + )} +
-
-
-
- +
+
+ {selectedPost && } +
-
-
-); +
+ ); +}; diff --git a/src/components/CommentItem.tsx b/src/components/CommentItem.tsx new file mode 100644 index 000000000..d94075299 --- /dev/null +++ b/src/components/CommentItem.tsx @@ -0,0 +1,50 @@ +import React, { memo } from 'react'; +import { Comment } from '../types/Comment'; +import { ErrorNotification } from './ErrorNotification'; + +type Props = { + comment: Comment; + onDelete: (id: number) => void; + deletingErrorPostIds: number[]; +}; + +export const CommentItem: React.FC = memo(function CommentItem({ + comment, + onDelete, + deletingErrorPostIds, +}) { + const { id, name, email, body } = comment; + + return ( + <> +
+
+ + {name} + + +
+ +
+ {body} +
+
+ + {deletingErrorPostIds.includes(id) && ( + + )} + + ); +}); diff --git a/src/components/CommentsList.tsx b/src/components/CommentsList.tsx new file mode 100644 index 000000000..4a9331778 --- /dev/null +++ b/src/components/CommentsList.tsx @@ -0,0 +1,30 @@ +import React, { memo } from 'react'; +import { Comment } from '../types/Comment'; +import { CommentItem } from './CommentItem'; + +type Props = { + comments: Comment[]; + onDelete: (id: number) => void; + deletingErrorPostIds: number[]; +}; + +export const CommentsList: React.FC = memo(function CommentsList({ + comments, + onDelete, + deletingErrorPostIds, +}) { + return ( + <> +

Comments:

+ + {comments.map(comment => ( + + ))} + + ); +}); diff --git a/src/components/ErrorNotification.tsx b/src/components/ErrorNotification.tsx new file mode 100644 index 000000000..3ec822120 --- /dev/null +++ b/src/components/ErrorNotification.tsx @@ -0,0 +1,15 @@ +import React, { memo } from 'react'; + +type Props = { + errorMessage: string; +}; + +export const ErrorNotification: React.FC = memo( + function ErrorNotification({ errorMessage }) { + return ( +
+ {errorMessage} +
+ ); + }, +); diff --git a/src/components/NewCommentForm.tsx b/src/components/NewCommentForm.tsx index 73a8a0b45..86334883b 100644 --- a/src/components/NewCommentForm.tsx +++ b/src/components/NewCommentForm.tsx @@ -1,8 +1,61 @@ -import React from 'react'; +// #region imports +import React, { memo, useState } from 'react'; +import cn from 'classnames'; +import { useForm } from 'react-hook-form'; +import { addPostComment } from '../services/comments'; +import { Comment } from '../types/Comment'; +import { ErrorNotification } from './ErrorNotification'; +// #endregion + +type Props = { + postId: number; + onCommentAdding: (comment: Comment) => void; +}; + +type FormData = { + name: string; + email: string; + body: string; +}; + +export const NewCommentForm: React.FC = memo(function NewCommentForm({ + postId, + onCommentAdding, +}) { + const { + register, + setValue, + handleSubmit, + formState: { errors }, + } = useForm(); + + const [isLoading, setIsLoading] = useState(false); + const [isAddingError, setIsAddingError] = useState(false); + + const onSubmit = handleSubmit(formData => { + const newComment = { + postId, + ...formData, + }; + + setIsAddingError(false); + setIsLoading(true); + + addPostComment(newComment) + .then(addedComment => { + onCommentAdding(addedComment); + setValue('body', ''); + }) + .catch(() => setIsAddingError(true)) + .finally(() => setIsLoading(false)); + }); + + const onReset = () => { + setIsAddingError(false); + }; -export const NewCommentForm: React.FC = () => { return ( -
+
@@ -41,28 +100,34 @@ export const NewCommentForm: React.FC = () => {
- - - + {errors.email && ( + + + + )}
-

- Email is required -

+ {errors.email && ( +

+ Email is required +

+ )}
@@ -73,20 +138,27 @@ export const NewCommentForm: React.FC = () => {