- {/* eslint-disable-next-line react/button-has-type */}
-
+
+
+
+
+
+
+ {/* eslint-disable-next-line react/button-has-type */}
+
+
+
+
+ {isError && (
+
+ Unable to add a comment
-
-
+ )}
+ >
);
};
diff --git a/src/components/PostDetails.tsx b/src/components/PostDetails.tsx
index ace945f0a..3888bdbab 100644
--- a/src/components/PostDetails.tsx
+++ b/src/components/PostDetails.tsx
@@ -1,117 +1,96 @@
-import React from 'react';
+import React, { useContext, useState } from 'react';
import { Loader } from './Loader';
import { NewCommentForm } from './NewCommentForm';
+import {
+ CommentsContext,
+ ErrorContext,
+ PostDataContext,
+} from './UserContext/UserContext';
export const PostDetails: React.FC = () => {
+ const postDetails = useContext(PostDataContext);
+ const { isLoading } = useContext(ErrorContext);
+ const { isError } = useContext(ErrorContext);
+ const { comments, handleRemoveComment } = useContext(CommentsContext);
+ const [click, setClick] = useState(false);
+
return (
- #18: voluptate et itaque vero tempora molestiae
+ {`#${postDetails.postData?.id}: ${postDetails.postData?.title}`}
- eveniet quo quis
- laborum totam consequatur non dolor
- ut et est repudiandae
- est voluptatem vel debitis et magnam
+ {postDetails.postData?.body}
-
-
-
- Something went wrong
-
-
-
- No comments yet
-
-
-
Comments:
+ {isLoading &&
}
-
-
-
-
- Some comment
+ {isError && (
+
+ Something went wrong
-
+ )}
-
-
-
- Misha Hrynko
-
+ {!comments.length && !isLoading && (
+
+ No comments yet
+
+ )}
-
-
-
- One more comment
-
-
+ {!isLoading && (
+
Comments:
+ )}
-
-
+
+ {comment.body}
+
+
+ ))
+ )}
-
- {'Multi\nline\ncomment'}
-
-
+ {!isLoading && (
+
+ )}
-
-
+ {click && postDetails.postData !== null && !isLoading && (
+ )}
+
);
diff --git a/src/components/PostsList.tsx b/src/components/PostsList.tsx
index 6e6efc0f3..1a604fbdd 100644
--- a/src/components/PostsList.tsx
+++ b/src/components/PostsList.tsx
@@ -1,85 +1,50 @@
-import React from 'react';
-
-export const PostsList: React.FC = () => (
-
-
Posts:
-
-
-
-
- # |
- Title |
- |
-
-
-
-
-
- 17 |
-
-
- fugit voluptas sed molestias voluptatem provident
- |
-
-
-
- |
-
-
-
- 18 |
-
-
- voluptate et itaque vero tempora molestiae
- |
-
-
-
- |
-
-
-
- 19 |
- adipisci placeat illum aut reiciendis qui |
-
-
-
- |
-
-
-
- 20 |
- doloribus ad provident suscipit at |
-
-
-
- |
-
-
-
-
-);
+import React, { useContext } from 'react';
+import classNames from 'classnames';
+import { PostDataContext, PostsContext } from './UserContext/UserContext';
+
+export const PostsList: React.FC = () => {
+ const posts = useContext(PostsContext);
+ const { postData, handlePost } = useContext(PostDataContext);
+
+ return (
+
+
Posts:
+
+
+
+
+ # |
+ Title |
+ |
+
+
+
+ {posts?.map(post => (
+
+ {post.id} |
+
+
+ {post.title}
+ |
+
+
+
+ |
+
+ ))}
+
+
+
+ );
+};
diff --git a/src/components/UserContext/UserContext.tsx b/src/components/UserContext/UserContext.tsx
new file mode 100644
index 000000000..933402cc7
--- /dev/null
+++ b/src/components/UserContext/UserContext.tsx
@@ -0,0 +1,167 @@
+import React, { useCallback, useEffect, useState } from 'react';
+import { User } from '../../types/User';
+import { getUsers } from '../../api/users';
+import { getPosts } from '../../api/posts';
+import { Post } from '../../types/Post';
+import { Comment } from '../../types/Comment';
+import { deleteComment, getComments } from '../../api/comments';
+
+type ErrorContextType = {
+ isLoading: boolean,
+ isError: boolean,
+ isLoadingPosts: boolean,
+};
+
+type UserType = {
+ user: User | null,
+ handleUserSelect: (id: User) => void,
+};
+
+type ComentsDataType = {
+ comments: Comment[],
+ newCommentSelect: (newComment: Comment) => void,
+ handleRemoveComment: (id: number) => void,
+};
+
+type PostDataType = {
+ postData: Post | null,
+ handlePost: (postDetails: Post) => void
+};
+
+type Props = {
+ children: React.ReactNode;
+};
+
+export const UsersContext = React.createContext
(null);
+export const ErrorContext
+ = React.createContext({} as ErrorContextType);
+export const UserContext = React.createContext({} as UserType);
+export const PostsContext
+ = React.createContext([]);
+export const CommentsContext
+ = React.createContext({} as ComentsDataType);
+export const PostDataContext
+ = React.createContext({} as PostDataType);
+
+export const UserProvider: React.FC = ({ children }) => {
+ const [users, setUsers] = useState(null);
+ const [isLoading, setIsloading] = useState(false);
+ const [isLoadingPosts, setIsLoaidingPosts] = useState(false);
+ const [isError, setIsError] = useState(false);
+ const [user, setUser] = useState(null);
+ const [posts, setPosts] = useState([]);
+ const [comments, setComments] = useState([]);
+ const [postData, setPostData] = useState(null);
+
+ const handleUserSelect = (id: User) => {
+ setUser(id);
+
+ setPostData(null);
+ };
+
+ const newCommentSelect = (newComment: Comment) => {
+ setComments(prevComments => [...prevComments, newComment]);
+ };
+
+ const handlePost = (postDetails: Post) => {
+ if (postData?.id === postDetails.id) {
+ setPostData(null);
+ } else {
+ setPostData(postDetails);
+ }
+ };
+
+ const loadUsersFromServer = async () => {
+ try {
+ const getUsersFromServer = await getUsers();
+
+ setUsers(getUsersFromServer);
+ } catch (error) {
+ setIsError(true);
+ }
+ };
+
+ const loadPostsFromServer = async () => {
+ try {
+ setIsLoaidingPosts(true);
+ const getPostsFromServer = await getPosts(user);
+
+ setPosts(getPostsFromServer);
+ } catch (error) {
+ setIsError(true);
+ setIsLoaidingPosts(false);
+ } finally {
+ setIsLoaidingPosts(false);
+ setIsError(false);
+ }
+ };
+
+ const loadCommentsFromServer = async () => {
+ try {
+ setIsloading(true);
+ const getCommentsFromServer = await getComments(postData);
+
+ setComments(getCommentsFromServer);
+ } catch (error) {
+ setIsError(true);
+ setIsloading(false);
+ } finally {
+ setIsloading(false);
+ setIsError(false);
+ }
+ };
+
+ const handleRemoveComment = async (id: number) => {
+ try {
+ await deleteComment(id);
+ const visibleComments = comments.filter(comment => {
+ return comment.id !== id;
+ });
+
+ setComments(visibleComments);
+ } catch {
+ setIsError(true);
+ }
+ };
+
+ const loadComments = useCallback(() => {
+ loadCommentsFromServer();
+ }, [postData]);
+
+ useEffect(() => {
+ loadUsersFromServer();
+ }, []);
+
+ useEffect(() => {
+ if (user) {
+ loadPostsFromServer();
+ }
+ }, [user]);
+
+ useEffect(() => {
+ if (postData) {
+ loadComments();
+ }
+ }, [postData]);
+
+ return (
+
+
+
+
+
+
+ {children}
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/UserSelector.tsx b/src/components/UserSelector.tsx
index cb83a8f68..02031768f 100644
--- a/src/components/UserSelector.tsx
+++ b/src/components/UserSelector.tsx
@@ -1,6 +1,22 @@
-import React from 'react';
+import React, { useContext, useState } from 'react';
+import { UsersContext, UserContext } from './UserContext/UserContext';
+import { User } from '../types/User';
export const UserSelector: React.FC = () => {
+ const users = useContext(UsersContext);
+ const [isOpen, setIsOpen] = useState(false);
+
+ const { handleUserSelect, user } = useContext(UserContext);
+
+ const handleMenu = () => {
+ setIsOpen(prev => !prev);
+ };
+
+ const handleUserId = (userId: User) => {
+ handleUserSelect(userId);
+ handleMenu();
+ };
+
return (
{
className="button"
aria-haspopup="true"
aria-controls="dropdown-menu"
+ onClick={handleMenu}
>
- Choose a user
+ {user ? (
+ {user.name}
+ ) : (
+ Choose a user
+ )}
@@ -21,15 +42,22 @@ export const UserSelector: React.FC = () => {
-
);
};
diff --git a/src/index.tsx b/src/index.tsx
index 6710ea0c2..2816a32b0 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,8 +1,10 @@
import ReactDOM from 'react-dom';
-
import { App } from './App';
+import { UserProvider } from './components/UserContext/UserContext';
ReactDOM.render(
- ,
+
+
+ ,
document.getElementById('root'),
);