-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add task #1177
base: master
Are you sure you want to change the base?
add task #1177
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
/* eslint-disable @typescript-eslint/indent */ | ||
|
||
import classNames from 'classnames'; | ||
|
||
import 'bulma/css/bulma.css'; | ||
|
@@ -8,53 +10,179 @@ import { PostsList } from './components/PostsList'; | |
import { PostDetails } from './components/PostDetails'; | ||
import { UserSelector } from './components/UserSelector'; | ||
import { Loader } from './components/Loader'; | ||
import { useEffect, useState } from 'react'; | ||
import { User } from './types/User'; | ||
import { | ||
addNewComment, | ||
deleteComment, | ||
getUserPostComments, | ||
getUserPosts, | ||
getUsers, | ||
} from './api/post'; | ||
import { Post } from './types/Post'; | ||
import { Comment, CommentData } from './types/Comment'; | ||
|
||
export const App = () => ( | ||
<main className="section"> | ||
<div className="container"> | ||
<div className="tile is-ancestor"> | ||
<div className="tile is-parent"> | ||
<div className="tile is-child box is-success"> | ||
<div className="block"> | ||
<UserSelector /> | ||
</div> | ||
export const App = () => { | ||
const [users, setUsers] = useState<User[]>([]); | ||
const [userSelected, setUserSelected] = useState<User | null>(null); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are initializing your state with props. This can lead to bugs and make the component harder to think about. You should avoid copying props into state. Instead, try to make the component fully controlled or fully uncontrolled with a key. You can read more about it here: Stack Overflow: Why is it bad to initialize state with props in React? |
||
const [showPostLoader, setShowPostLoader] = useState<boolean>(false); | ||
const [showCommentLoader, setShowCommentLoader] = useState<boolean>(false); | ||
const [isAddingComment, setIsAddingComment] = useState(false); | ||
const [userPosts, setUserPosts] = useState<Post[]>([]); | ||
const [selectedPost, setSelectedPost] = useState<Post | null>(null); | ||
const [isSidebarVisible, setIsSidebarVisible] = useState<number | null>(null); | ||
const [postComments, setPostComments] = useState<Comment[]>([]); | ||
const [hasPostError, setHasPostError] = useState<boolean>(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The variable |
||
const [hasCommentError, setHasCommentError] = useState<boolean>(false); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The variable |
||
const [isCommentFormVisible, setIsCommentFormVisible] = useState(false); | ||
|
||
<div className="block" data-cy="MainContent"> | ||
<p data-cy="NoSelectedUser">No user selected</p> | ||
useEffect(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should handle errors that might occur during API calls. Wrap the getUsers() call in a try-catch block and set an appropriate state in case of an error. |
||
getUsers() | ||
.then(res => { | ||
setUsers(res as User[]); | ||
}) | ||
.catch(() => new Error('Failed to fetch users')); | ||
}, []); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In your There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a good practice to handle errors properly. In your case, if the request fails, you just throw a new Error, but nothing catches it. It's better to show some notification to the user about the problem. You can use a try-catch block for error handling. |
||
|
||
<Loader /> | ||
const fetchUserPosts = (user: User) => { | ||
setShowPostLoader(true); | ||
getUserPosts(user.id) | ||
.then(res => { | ||
setUserPosts(res as Post[]); | ||
setHasPostError(false); | ||
}) | ||
.catch(() => { | ||
setHasPostError(true); | ||
}) | ||
.finally(() => { | ||
setShowPostLoader(false); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar to the previous comment, you're catching errors here but not providing any feedback to the user. You should handle these errors in a way that the user is informed about it. You can do this by setting an error state and displaying a message in the UI when an error occurs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are using the |
||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function |
||
|
||
<div | ||
className="notification is-danger" | ||
data-cy="PostsLoadingError" | ||
> | ||
Something went wrong! | ||
</div> | ||
const fetchPostComments = (currentPost: Post) => { | ||
setIsSidebarVisible(currentPost.id); | ||
setShowCommentLoader(true); | ||
|
||
setSelectedPost(currentPost); | ||
|
||
getUserPostComments(currentPost.id) | ||
.then(res => { | ||
setPostComments(res as Comment[]); | ||
setHasCommentError(false); | ||
}) | ||
.catch(() => { | ||
setHasCommentError(true); | ||
}) | ||
.finally(() => { | ||
setShowCommentLoader(false); | ||
}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue here with error handling. You're catching the error but not doing anything with it. Make sure to handle these errors properly so the user is informed about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You are using the |
||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function |
||
|
||
const removeComment = (commentId: number) => { | ||
deleteComment(commentId) | ||
.then(() => { | ||
setPostComments(prevPostComments => | ||
prevPostComments.filter( | ||
(comment: Comment) => comment.id !== commentId, | ||
), | ||
); | ||
}) | ||
.catch(() => new Error('Failed to delete comment')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, you're catching the error but not handling it. Make sure to provide some feedback to the user when an error occurs. |
||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should handle errors properly. In your case, if the request fails, you just throw a new Error, but nothing catches it. It's better to show some notification to the user about the problem. You can use a try-catch block for error handling. |
||
|
||
const createComment = (newComment: CommentData) => { | ||
setIsAddingComment(true); | ||
addNewComment(newComment) | ||
.then(res => { | ||
setPostComments([...postComments, res as Comment]); | ||
setIsAddingComment(false); | ||
}) | ||
.catch(() => new Error('Failed to add comment')); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're catching the error but not handling it. Consider providing some feedback to the user when an error occurs. |
||
}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You should handle errors properly. In your case, if the request fails, you just throw a new Error, but nothing catches it. It's better to show some notification to the user about the problem. You can use a try-catch block for error handling. |
||
|
||
<div className="notification is-warning" data-cy="NoPostsYet"> | ||
No posts yet | ||
return ( | ||
<main className="section"> | ||
<div className="container"> | ||
<div className="tile is-ancestor"> | ||
<div className="tile is-parent"> | ||
<div className="tile is-child box is-success"> | ||
<div className="block"> | ||
<UserSelector | ||
users={users} | ||
setUserSelected={setUserSelected} | ||
userSelected={userSelected} | ||
handleUserPosts={fetchUserPosts} | ||
setShowSideBar={setIsSidebarVisible} | ||
/> | ||
</div> | ||
|
||
<PostsList /> | ||
<div className="block" data-cy="MainContent"> | ||
{!userSelected && ( | ||
<p data-cy="NoSelectedUser">No user selected</p> | ||
)} | ||
|
||
{showPostLoader && <Loader />} | ||
|
||
{hasPostError && ( | ||
<div | ||
className="notification is-danger" | ||
data-cy="PostsLoadingError" | ||
> | ||
Something went wrong! | ||
</div> | ||
)} | ||
|
||
{userPosts.length > 0 && !showPostLoader && ( | ||
<PostsList | ||
userPosts={userPosts} | ||
handleShowComment={fetchPostComments} | ||
showSideBar={isSidebarVisible} | ||
setShowSideBar={setIsSidebarVisible} | ||
setShowCommentForm={setIsCommentFormVisible} | ||
/> | ||
)} | ||
{userSelected && | ||
userPosts.length === 0 && | ||
!showPostLoader && | ||
!hasPostError && ( | ||
<div | ||
className="notification is-warning" | ||
data-cy="NoPostsYet" | ||
> | ||
No posts yet | ||
</div> | ||
)} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div | ||
data-cy="Sidebar" | ||
className={classNames( | ||
'tile', | ||
'is-parent', | ||
'is-8-desktop', | ||
'Sidebar', | ||
'Sidebar--open', | ||
)} | ||
> | ||
<div className="tile is-child box is-success "> | ||
<PostDetails /> | ||
<div | ||
data-cy="Sidebar" | ||
className={classNames( | ||
'tile', | ||
'is-parent', | ||
'is-8-desktop', | ||
'Sidebar', | ||
{ 'Sidebar--open': isSidebarVisible }, | ||
)} | ||
> | ||
<div className="tile is-child box is-success "> | ||
<PostDetails | ||
isCommentLoading={showCommentLoader} | ||
postComments={postComments} | ||
selectedPost={selectedPost} | ||
errorsComment={hasCommentError} | ||
onDeleteComment={removeComment} | ||
onAddComment={createComment} | ||
isButtonAddLoading={isAddingComment} | ||
onShowCommentFormChange={setIsCommentFormVisible} | ||
isCommentFormVisible={isCommentFormVisible} | ||
userSelected={userSelected} | ||
/> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</main> | ||
); | ||
</main> | ||
); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import { CommentData } from '../types/Comment'; | ||
import { client } from '../utils/fetchClient'; | ||
|
||
export const getUsers = () => { | ||
return client.get('/users'); | ||
}; | ||
|
||
export const getUserPosts = (userId: number) => { | ||
return client.get(`/posts?userId=${userId}`); | ||
}; | ||
|
||
export const getUserPostComments = (postId: number) => { | ||
return client.get(`/comments?postId=${postId}`); | ||
}; | ||
|
||
export const addNewComment = (newComment: CommentData) => { | ||
return client.post('/comments', newComment); | ||
}; | ||
|
||
export const deleteComment = (commentId: number) => { | ||
return client.delete(`/comments/${commentId}`); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are initializing your state with props. This can lead to bugs and make the component harder to think about. You should avoid copying props into state. Instead, try to make the component fully controlled or fully uncontrolled with a key. You can read more about it here: Stack Overflow: Why is it bad to initialize state with props in React?