Skip to content
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

implement functionality for dynamic list of posts #921

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

voievodik
Copy link

@voievodik voievodik commented Sep 24, 2023

Copy link

@BudnikOleksii BudnikOleksii left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work 👍
Let's improve your solution slightly

src/App.tsx Outdated
Comment on lines 55 to 62
{user && posts.length === 0 ? (
<div
className="notification is-warning"
data-cy="NoPostsYet"
>
No posts yet
</div>
) : null}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{user && posts.length === 0 ? (
<div
className="notification is-warning"
data-cy="NoPostsYet"
>
No posts yet
</div>
) : null}
{user && posts.length === 0 && (
<div
className="notification is-warning"
data-cy="NoPostsYet"
>
No posts yet
</div>
)}

You can use just and operator in this case

src/App.tsx Outdated
Comment on lines 64 to 66
{posts.length > 0 && user ? (
<PostsList />
) : null}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same

Comment on lines 12 to 22
// export const createComment = (data: Comment) => {
// return client.post<Comment>('/comments', data);
// };

export const createComment = ({
name, email, body, postId,
}: Omit<Comment, 'id'>) => {
return client.post<Comment>('/comments', {
name, email, body, postId,
});
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// export const createComment = (data: Comment) => {
// return client.post<Comment>('/comments', data);
// };
export const createComment = ({
name, email, body, postId,
}: Omit<Comment, 'id'>) => {
return client.post<Comment>('/comments', {
name, email, body, postId,
});
};
export const createComment = (comment: Omit<Comment, 'id'>) => {
return client.post<Comment>('/comments', comment);
};

Don't leave comments, and you don't need destructing in this case

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I use this shortcut, the comment will not be created on the server and I get an error

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO - You are not sure what data would actually be passed to this function - so explicitly sending only the required data is OK

Comment on lines 21 to 27
const handleChangeForm = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
event.preventDefault();

setFormData(prev => ({ ...prev, [event.target.name]: event.target.value }));
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const handleChangeForm = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
event.preventDefault();
setFormData(prev => ({ ...prev, [event.target.name]: event.target.value }));
};
const handleChangeForm = (
event: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>,
) => {
const { name, value } = event.target;
setFormData(prev => ({ ...prev, [name]: value }));
};

Why do you do event.preventDefault();?

Add
</button>
</div>
{/* is-loading */}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't leave comments


export const PostDetails: React.FC = () => {
const { post } = useContext(PostsContext);
const { comments, setComments } = useContext(CommentsContext);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can create a hook for your contexts and in this case, you don't need to pass context every time:

const useComments = () => useContext(CommentsContext);

Comment on lines 18 to 22
.then(() => {
setComments(prevComments => {
return prevComments.filter(({ id }) => id !== commentId);
});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add catch block

Comment on lines 72 to 86
<article className="message is-small" data-cy="Comment" key={id}>
<div className="message-header">
<a href={`mailto:${email}`} data-cy="CommentAuthor">
{name}
</a>
<button
data-cy="CommentDelete"
type="button"
className="delete is-small"
aria-label="delete"
onClick={() => handleDeleteComment(id)}
>
delete button
</button>
</div>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create a Comment component

</td>
</tr>
return (
<tr data-cy="Post" key={id}>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create Post component

Copy link

@DenisChakhalian DenisChakhalian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good job!

Comment on lines 34 to 37
data-cy="PostButton"
className={classnames('button is-link', {
'is-light': post?.id !== id,
})}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

that is better

Suggested change
data-cy="PostButton"
className={classnames('button is-link', {
'is-light': post?.id !== id,
})}
data-cy="PostButton"
className={classnames('button', 'is-link', {
'is-light': post?.id !== id,
})}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

Comment on lines 177 to 179
<button type="submit" className="button is-link ">
Add
</button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<button type="submit" className="button is-link ">
Add
</button>
<button type="submit" className="button is-link">
Add
</button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

Comment on lines +10 to +18
<UsersProvider>
<PostsProvider>
<CommentsProvider>
<ErrorProvider>
<App />
</ErrorProvider>
</CommentsProvider>
</PostsProvider>
</UsersProvider>,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can create a component that will wrap the App with all providers

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense - you should do it next time

Copy link

@roman-mirzoian roman-mirzoian left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job, but let's polish your code.

Comment on lines 34 to 37
data-cy="PostButton"
className={classnames('button is-link', {
'is-light': post?.id !== id,
})}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

Comment on lines 177 to 179
<button type="submit" className="button is-link ">
Add
</button>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point.

src/components/PostDetails.tsx Outdated Show resolved Hide resolved
src/components/PostDetails.tsx Outdated Show resolved Hide resolved
src/components/PostDetails.tsx Outdated Show resolved Hide resolved
Copy link

@alexander-ignatow alexander-ignatow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall - good job! 👍

You are good at writing components - but there are some issues with overall architecture and components responsibility

Let's move on with this solution, but here are the items to keep in mind for the future:

  1. Mind the naming - all component and function names should be as descriptive as possible. For instance CurrentPost suggests that the component renders some specific post that the user is working on. But in your app, it is just an element of the list, so Post or even PostItem fits better. Also - mind the grammar ;)
  2. Try organizing components in the folders: for instance, you can create a subfolder 'components/PostList' and move all post-related components there (PostList, CurrentPost, CurrentComment, etc.)
  3. Don't overuse contexts - while this is a powerful tool, it has "dark sides". One of them is making the code more "coupled". Try making components as "dumb" and isolated as possible - it improves testability, makes supporting the code easier, etc. For instance - I would remove the PostsContext call from the PostList and simply pass posts as an external property.

Comment on lines +14 to +15
user: null,
setUser: () => {},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calling this currentUser or selectedUser would be a bit more readable

Comment on lines +14 to +15
post: null,
setPost: () => {},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as with user context - better call it selectedPost, etc


interface ErrorContextType {
isErrorHappen: boolean;
setIsErrorHappen: React.Dispatch<React.SetStateAction<boolean>>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar issue :)

Better hasErrorHappened or just hasError, etc

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From how I see your scenario - it makes sense to merge CommentsContext and PostsContext

The thing is, that you have currentPost in the PostsContext but comments do not make any sense without the Post.

The main idea is minimizing the number of contexts, as managing large number of contexts is not the best experience

Comment on lines +58 to +70
{isPostsExist && (
<div
className="notification is-warning"
data-cy="NoPostsYet"
>
No posts yet
</div>
)}

<div
className="notification is-danger"
data-cy="PostsLoadingError"
>
Something went wrong!
</div>
{isPostListShown && (
<PostsList />
)}
</>

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are reading the posts in the App only to show this section

Possibly it makes sense to move the block "No posts yet" to the PostsList

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming issue: just Comment looks better

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming issue: just Post or PostItem looks better

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants