From 07d4452f302978593b592b4e1bc5665961cd458e Mon Sep 17 00:00:00 2001 From: OkMoroz Date: Thu, 19 Dec 2024 20:32:49 +0200 Subject: [PATCH] added solutions --- src/App.tsx | 71 ++--------- src/AppWithContexts.tsx | 104 ++++++++++++++++ src/api/comments.ts | 14 +++ src/api/posts.ts | 6 + src/api/users.ts | 6 + src/components/NewCommentForm.tsx | 169 +++++++++++++++++++++----- src/components/PostDetails.tsx | 196 ++++++++++++++++-------------- src/components/PostsList.tsx | 132 +++++++++----------- src/components/UserSelector.tsx | 76 +++++++++--- src/context/UserContext.tsx | 25 ++++ src/types/Comment.ts | 2 +- 11 files changed, 527 insertions(+), 274 deletions(-) create mode 100644 src/AppWithContexts.tsx create mode 100644 src/api/comments.ts create mode 100644 src/api/posts.ts create mode 100644 src/api/users.ts create mode 100644 src/context/UserContext.tsx diff --git a/src/App.tsx b/src/App.tsx index 017957182..6ed389b3c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,60 +1,11 @@ -import classNames from 'classnames'; - -import 'bulma/css/bulma.css'; -import '@fortawesome/fontawesome-free/css/all.css'; -import './App.scss'; - -import { PostsList } from './components/PostsList'; -import { PostDetails } from './components/PostDetails'; -import { UserSelector } from './components/UserSelector'; -import { Loader } from './components/Loader'; - -export const App = () => ( -
-
-
-
-
-
- -
- -
-

No user selected

- - - -
- Something went wrong! -
- -
- No posts yet -
- - -
-
-
- -
-
- -
-
-
-
-
-); +import React from 'react'; +import { UserContextProvider } from './context/UserContext'; +import { AppWithContexts } from './AppWithContexts'; + +export const App: React.FC = () => { + return ( + + + + ); +}; diff --git a/src/AppWithContexts.tsx b/src/AppWithContexts.tsx new file mode 100644 index 000000000..2260fabb3 --- /dev/null +++ b/src/AppWithContexts.tsx @@ -0,0 +1,104 @@ +import React, { useContext, useEffect, useState } from 'react'; +import 'bulma/bulma.sass'; +import '@fortawesome/fontawesome-free/css/all.css'; +import './App.scss'; + +import classNames from 'classnames'; +import { PostsList } from './components/PostsList'; +import { PostDetails } from './components/PostDetails'; +import { UserSelector } from './components/UserSelector'; +import { UserContext } from './context/UserContext'; +import { getPosts } from './api/posts'; +import { Post } from './types/Post'; +import { Loader } from './components/Loader'; + +export const AppWithContexts: React.FC = () => { + const selectedUser = useContext(UserContext); + const [posts, setPosts] = useState([]); + const [error, setError] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const [selectedPost, setSelectedPost] = useState(null); + + useEffect(() => { + if (!selectedUser) { + return; + } + + setPosts([]); + setError(false); + setIsLoading(true); + + setSelectedPost(null); + + getPosts(selectedUser.id) + .then(setPosts) + .catch(() => setError(true)) + .finally(() => setIsLoading(false)); + }, [selectedUser]); + + return ( +
+
+
+
+
+
+ +
+ +
+ {!selectedUser && ( +

No user selected

+ )} + + {selectedUser && isLoading && } + + {error && ( +
+ Something went wrong! +
+ )} + + {selectedUser && + !isLoading && + !error && + (!posts.length ? ( +
+ No posts yet +
+ ) : ( + + ))} +
+
+
+ +
+
+ {selectedPost && } +
+
+
+
+
+ ); +}; diff --git a/src/api/comments.ts b/src/api/comments.ts new file mode 100644 index 000000000..03b447eb6 --- /dev/null +++ b/src/api/comments.ts @@ -0,0 +1,14 @@ +import { Comment, CommentData } from '../types/Comment'; +import { client } from '../utils/fetchClient'; + +export const getComments = (postId: number) => { + return client.get(`/comments?postId=${postId}`); +}; + +export const deleteComment = (commentId: number) => { + return client.delete(`/comments/${commentId}`); +}; + +export const addComment = (newComment: CommentData) => { + return client.post('/comments', newComment); +}; diff --git a/src/api/posts.ts b/src/api/posts.ts new file mode 100644 index 000000000..a6a1739ec --- /dev/null +++ b/src/api/posts.ts @@ -0,0 +1,6 @@ +import { Post } from '../types/Post'; +import { client } from '../utils/fetchClient'; + +export const getPosts = (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..386bfacd5 --- /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..592a3aa4b 100644 --- a/src/components/NewCommentForm.tsx +++ b/src/components/NewCommentForm.tsx @@ -1,8 +1,91 @@ -import React from 'react'; +import React, { Dispatch, SetStateAction, useState } from 'react'; +import { addComment } from '../api/comments'; +import classNames from 'classnames'; +import { Comment } from '../types/Comment'; + +type Props = { + postId: number; + setComments: Dispatch>; + setIsNewCommentError: (newState: boolean) => void; +}; + +export const NewCommentForm: React.FC = ({ + postId, + setComments, + setIsNewCommentError, +}) => { + const [authorName, setAuthorName] = useState(''); + const [nameError, setNameError] = useState(false); + + const [authorEmail, setAuthorEmail] = useState(''); + const [emailError, setEmailError] = useState(false); + + const [text, setText] = useState(''); + const [textError, setTextError] = useState(false); + + const [isLoading, setIsLoading] = useState(false); + + const handleOnNameChange = (event: React.ChangeEvent) => { + setNameError(false); + setAuthorName(event.target.value); + }; + + const handleOnEmailChange = (event: React.ChangeEvent) => { + setEmailError(false); + setAuthorEmail(event.target.value); + }; + + const handleOnTextChange = ( + event: React.ChangeEvent, + ) => { + setTextError(false); + setText(event.target.value); + }; + + const handleOnSubmit = (event: React.FormEvent) => { + event.preventDefault(); + + if (!authorName || !authorEmail || !text) { + setNameError(!authorName); + setEmailError(!authorEmail); + setTextError(!text); + + return; + } + + setIsLoading(true); + + const newComment = { + postId: postId, + name: authorName, + email: authorEmail, + body: text, + }; + + addComment(newComment) + .then(commentToAdd => { + setComments((prevComments: Comment[]) => [ + ...prevComments, + commentToAdd as Comment, + ]); + setText(''); + }) + .catch(() => setIsNewCommentError(true)) + .finally(() => setIsLoading(false)); + }; + + const handleOnClear = () => { + setAuthorName(''); + setAuthorEmail(''); + setText(''); + + setNameError(false); + setEmailError(false); + setTextError(false); + }; -export const NewCommentForm: React.FC = () => { return ( -
+
-

- Name is required -

+ {nameError && ( +

+ Name is required +

+ )}
@@ -41,28 +130,34 @@ export const NewCommentForm: React.FC = () => {
handleOnEmailChange(e)} /> - - - + {emailError && ( + + + + )}
-

- Email is required -

+ {emailError && ( +

+ Email is required +

+ )}
@@ -74,26 +169,40 @@ export const NewCommentForm: React.FC = () => {