Skip to content

Commit

Permalink
add task solution
Browse files Browse the repository at this point in the history
  • Loading branch information
Kirill1908 committed Oct 15, 2024
1 parent 8b7ce12 commit 4c1970b
Show file tree
Hide file tree
Showing 8 changed files with 577 additions and 263 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@ Install Prettier Extention and use this [VSCode settings](https://mate-academy.g
1. Implement comment deletion
- Delete the commnet immediately not waiting for the server response to improve the UX.
1. (*) Handle `Add` and `Delete` errors so the user can retry

[DEMO LINK](https://Kirill1908.github.io/react_dynamic-list-of-posts/)
207 changes: 167 additions & 40 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,60 +1,187 @@
import classNames from 'classnames';
/* eslint-disable @typescript-eslint/indent */

import classNames from 'classnames';
import 'bulma/css/bulma.css';
import '@fortawesome/fontawesome-free/css/all.css';
import './App.scss';
import { useEffect, useState } from 'react';

import { PostsList } from './components/PostsList';
import { PostDetails } from './components/PostDetails';
import { UserSelector } from './components/UserSelector';
import { PostDetails } from './components/PostDetails';
import { PostsList } from './components/PostsList';
import { Loader } from './components/Loader';
import { Comment, CommentData } from './types/Comment';
import { User } from './types/User';
import { Post } from './types/Post';
import {
addNewComment,
deleteComment,
getUserPostComments,
getUserPosts,
getUsers,
} from './api/post';

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);
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);
const [hasCommentError, setHasCommentError] = useState<boolean>(false);
const [isCommentFormVisible, setIsCommentFormVisible] = useState(false);

<div className="block" data-cy="MainContent">
<p data-cy="NoSelectedUser">No user selected</p>
useEffect(() => {
getUsers()
.then(res => {
setUsers(res as User[]);
})
.catch(() => new Error('Failed to fetch users'));
}, []);

<Loader />
const fetchUserPosts = (user: User) => {
setShowPostLoader(true);
getUserPosts(user.id)
.then(res => {
setUserPosts(res as Post[]);
setHasPostError(false);
})
.catch(() => {
setHasPostError(true);
})
.finally(() => {
setShowPostLoader(false);
});
};

<div
className="notification is-danger"
data-cy="PostsLoadingError"
>
Something went wrong!
</div>
const fetchPostComments = (currentPost: Post) => {
setIsSidebarVisible(currentPost.id);
setShowCommentLoader(true);

setSelectedPost(currentPost);

<div className="notification is-warning" data-cy="NoPostsYet">
No posts yet
getUserPostComments(currentPost.id)
.then(res => {
setPostComments(res as Comment[]);
setHasCommentError(false);
})
.catch(() => {
setHasCommentError(true);
})
.finally(() => {
setShowCommentLoader(false);
});
};

const removeComment = (commentId: number) => {
deleteComment(commentId)
.then(() => {
setPostComments(prevPostComments =>
prevPostComments.filter(
(comment: Comment) => comment.id !== commentId,
),
);
})
.catch(() => new Error('Failed to delete comment'));
};

const createComment = (newComment: CommentData) => {
setIsAddingComment(true);
addNewComment(newComment)
.then(res => {
setPostComments([...postComments, res as Comment]);
setIsAddingComment(false);
})
.catch(() => new Error('Failed to add comment'));
};

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>
);
};
22 changes: 22 additions & 0 deletions src/api/post.ts
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}`);
};
Loading

0 comments on commit 4c1970b

Please sign in to comment.