diff --git a/src/App.tsx b/src/App.tsx index 017957182..934f58758 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,3 +1,4 @@ +import { useState, useEffect } from 'react'; import classNames from 'classnames'; import 'bulma/css/bulma.css'; @@ -8,53 +9,102 @@ import { PostsList } from './components/PostsList'; import { PostDetails } from './components/PostDetails'; import { UserSelector } from './components/UserSelector'; import { Loader } from './components/Loader'; +import { User } from './types/User'; +import { Post } from './types/Post'; +import { getUserPosts } from './api/posts'; -export const App = () => ( -
-
-
-
-
-
- -
+export const App = () => { + const [selectedUser, setSelectedUser] = useState(null); + const [posts, setPosts] = useState([]); + const [postsIsLoading, setPostsIsLoading] = useState(false); + const [hasPostsError, setHasPostsError] = useState(''); -
-

No user selected

+ const [chosenPost, setChosenPost] = useState(null); - + const hasNoPosts = + selectedUser && !postsIsLoading && !hasPostsError && !posts.length; -
- Something went wrong! -
+ useEffect(() => { + if (!selectedUser) { + return; + } + + setPostsIsLoading(true); + setHasPostsError(''); + setPosts([]); + setChosenPost(null); -
- No posts yet + getUserPosts(selectedUser.id) + .then(setPosts) + .catch(() => setHasPostsError('Something went wrong!')) + .finally(() => setPostsIsLoading(false)); + }, [selectedUser]); + + return ( +
+
+
+
+
+
+
- +
+ {!selectedUser && ( +

No user selected

+ )} + + {postsIsLoading && } + + {!postsIsLoading && hasPostsError && ( +
+ {hasPostsError} +
+ )} + + {hasNoPosts && ( +
+ No posts yet +
+ )} + + {!postsIsLoading && posts.length > 0 && ( + + )} +
-
-
-
- +
+
+ {chosenPost && } +
-
-
-); +
+ ); +}; diff --git a/src/api/comments.ts b/src/api/comments.ts new file mode 100644 index 000000000..7108ba40e --- /dev/null +++ b/src/api/comments.ts @@ -0,0 +1,19 @@ +import { Comment } from '../types/Comment'; +import { client } from '../utils/fetchClient'; + +export const getPostComments = (postId: number) => { + return client.get(`/comments?postId=${postId}`); +}; + +export const postComment = ({ + name, + email, + body, + postId, +}: Omit) => { + return client.post('/comments', { name, email, body, postId }); +}; + +export const deleteComment = (commentId: number) => { + return client.delete(`/comments/${commentId}`); +}; diff --git a/src/api/posts.ts b/src/api/posts.ts new file mode 100644 index 000000000..93fadf72b --- /dev/null +++ b/src/api/posts.ts @@ -0,0 +1,6 @@ +import { Post } from '../types/Post'; +import { client } from '../utils/fetchClient'; + +export const getUserPosts = (userId: number) => { + return client.get(`/posts?userId=${userId}`); +}; diff --git a/src/api/users.ts b/src/api/users.ts new file mode 100644 index 000000000..816c8274b --- /dev/null +++ b/src/api/users.ts @@ -0,0 +1,6 @@ +import { User } from '../types/User'; +import { client } from '../utils/fetchClient'; + +export const getUsers = () => { + return client.get('/users'); +}; diff --git a/src/components/NewCommentForm.tsx b/src/components/NewCommentForm.tsx index 73a8a0b45..8ccb669bd 100644 --- a/src/components/NewCommentForm.tsx +++ b/src/components/NewCommentForm.tsx @@ -1,37 +1,124 @@ -import React from 'react'; +import React, { useState } from 'react'; +import cn from 'classnames'; +import { Post } from '../types/Post'; +import { CommentData } from '../types/Comment'; + +type Props = { + post: Post; + addComment: (v: CommentData & { postId: number }) => Promise; +}; + +export const NewCommentForm: React.FC = ({ post, addComment }) => { + const [name, setName] = useState(''); + const [hasNameError, setHasNameError] = useState(false); + + const [email, setEmail] = useState(''); + const [hasEmailError, setHasEmailError] = useState(false); + + const [body, setBody] = useState(''); + const [hasBodyError, setHasBodyError] = useState(false); + + const [isSending, setIsSending] = useState(false); + + const handleNameChange = (e: React.ChangeEvent) => { + setName(e.target.value); + setHasNameError(false); + }; + + const handleEmailChange = (e: React.ChangeEvent) => { + setEmail(e.target.value); + setHasEmailError(false); + }; + + const handleBodyChange = (e: React.ChangeEvent) => { + setBody(e.target.value); + setHasBodyError(false); + }; + + const reset = () => { + setName(''); + setHasNameError(false); + + setEmail(''); + setHasEmailError(false); + + setBody(''); + setHasBodyError(false); + }; + + const submit = (e: React.FormEvent) => { + e.preventDefault(); + + setIsSending(true); + + const nameError = !name.trim(); + const emailError = !email.trim(); + const bodyError = !body.trim(); + + setHasNameError(nameError); + setHasEmailError(emailError); + setHasBodyError(bodyError); + + if (nameError || emailError || bodyError) { + setIsSending(false); + + return; + } + + const newComment = { + name, + body, + email, + postId: post.id, + }; + + addComment(newComment).finally(() => setIsSending(false)); + reset(); + }; -export const NewCommentForm: React.FC = () => { return ( -
+
-
+
- - - + {hasNameError && ( + + + + )}
-

- Name is required -

+ {hasNameError && ( +

+ Name is required +

+ )}
@@ -39,30 +126,42 @@ export const NewCommentForm: React.FC = () => { Author Email -
+
- - - + {hasEmailError && ( + + + + )}
-

- Email is required -

+ {hasEmailError && ( +

+ Email is required +

+ )}
@@ -72,21 +171,32 @@ export const NewCommentForm: React.FC = () => {