From 460a06e782e188707b08165829cc8184d35084ef Mon Sep 17 00:00:00 2001 From: Tanya Baletska Date: Fri, 8 Nov 2024 16:26:03 +0200 Subject: [PATCH] add task solution --- package-lock.json | 12 +- package.json | 2 +- src/App.tsx | 132 ++++++++++++++------ src/components/NewCommentForm.tsx | 173 +++++++++++++++++++------- src/components/PostDetails.tsx | 198 +++++++++++++++++------------- src/components/PostsList.tsx | 138 +++++++++------------ src/components/UserSelector.tsx | 88 ++++++++++--- src/utils/fetchClient.ts | 28 +++++ 8 files changed, 500 insertions(+), 271 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d91573bb..f6d70b30a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ }, "devDependencies": { "@cypress/react18": "^2.0.1", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^1.9.12", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^20.14.10", @@ -1183,10 +1183,11 @@ } }, "node_modules/@mate-academy/scripts": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.8.5.tgz", - "integrity": "sha512-mHRY2FkuoYCf5U0ahIukkaRo5LSZsxrTSgMJheFoyf3VXsTvfM9OfWcZIDIDB521kdPrScHHnRp+JRNjCfUO5A==", + "version": "1.9.12", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.9.12.tgz", + "integrity": "sha512-/OcmxMa34lYLFlGx7Ig926W1U1qjrnXbjFJ2TzUcDaLmED+A5se652NcWwGOidXRuMAOYLPU2jNYBEkKyXrFJA==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", @@ -3256,7 +3257,8 @@ "node_modules/classnames": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==" + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" }, "node_modules/clean-stack": { "version": "2.2.0", diff --git a/package.json b/package.json index 4b5c5ff54..9786f26cd 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ }, "devDependencies": { "@cypress/react18": "^2.0.1", - "@mate-academy/scripts": "^1.8.5", + "@mate-academy/scripts": "^1.9.12", "@mate-academy/students-ts-config": "*", "@mate-academy/stylelint-config": "*", "@types/node": "^20.14.10", diff --git a/src/App.tsx b/src/App.tsx index 017957182..29536be4c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,4 +1,8 @@ -import classNames from 'classnames'; +import { useEffect, useState } from 'react'; +import { getUsers, getUserPosts } from './utils/fetchClient'; +import { User } from './types/User'; +import { Post } from './types/Post'; +import cn from 'classnames'; import 'bulma/css/bulma.css'; import '@fortawesome/fontawesome-free/css/all.css'; @@ -9,52 +13,102 @@ import { PostDetails } from './components/PostDetails'; import { UserSelector } from './components/UserSelector'; import { Loader } from './components/Loader'; -export const App = () => ( -
-
-
-
-
-
- -
+export const App: React.FC = () => { + const [users, setUsers] = useState([]); + const [posts, setPosts] = useState([]); + const [currUser, setCurrUser] = useState(null); + const [currPost, setCurrPost] = useState(null); + const [openModal, setOpenModal] = useState(false); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(false); -
-

No user selected

+ const searchUserPosts = (userId: number) => { + getUserPosts(userId) + .then(setPosts) + .catch(() => setError(true)) + .finally(() => setLoading(false)); + }; - + useEffect(() => { + getUsers().then(setUsers); + }, []); -
- Something went wrong! -
+ useEffect(() => { + if (currUser) { + setLoading(true); + searchUserPosts(currUser.id); + setCurrPost(null); + setOpenModal(false); + } + }, [currUser]); -
- No posts yet + return ( +
+
+
+
+
+
+
- +
+ {!currUser &&

No user selected

} + + {!loading && + !error && + currUser && + (posts.length > 0 ? ( + + ) : ( +
+ No posts yet +
+ ))} + + {loading && } + + {error && ( +
+ Something went wrong! +
+ )} +
-
- -
-
- +
+
+ {currPost && ( + + )} +
-
-
-); +
+ ); +}; diff --git a/src/components/NewCommentForm.tsx b/src/components/NewCommentForm.tsx index 73a8a0b45..3d8b9ec96 100644 --- a/src/components/NewCommentForm.tsx +++ b/src/components/NewCommentForm.tsx @@ -1,99 +1,188 @@ -import React from 'react'; +import React, { useState, ChangeEvent, FormEvent } from 'react'; +import { CommentData } from '../types/Comment'; +import cn from 'classnames'; + +type Props = { + loader: boolean; + onAdd: (newComment: CommentData) => Promise; +}; + +export const NewCommentForm: React.FC = ({ loader, onAdd }) => { + const [newComment, setNewComment] = useState({ + name: '', + email: '', + body: '', + }); + const [touched, setTouched] = useState({ + name: false, + email: false, + body: false, + }); + + const handleInputChange = ( + e: ChangeEvent, + ) => { + const { name, value } = e.target; + + setNewComment(prevComment => ({ ...prevComment, [name]: value })); + setTouched(prevTouched => ({ ...prevTouched, [name]: true })); + }; + + const handleReset = () => { + setNewComment({ + name: '', + email: '', + body: '', + }); + setTouched({ + name: false, + email: false, + body: false, + }); + }; + + const handleSubmit = async (e: FormEvent) => { + e.preventDefault(); + + const isNameEmpty = newComment.name === ''; + const isEmailEmpty = newComment.email === ''; + const isBodyEmpty = newComment.body === ''; + + if (isNameEmpty || isEmailEmpty || isBodyEmpty) { + setTouched({ + name: isNameEmpty, + email: isEmailEmpty, + body: isBodyEmpty, + }); + + return; + } + + onAdd(newComment); + setNewComment(prevComment => ({ ...prevComment, body: '' })); + setTouched({ name: false, email: false, body: false }); + }; -export const NewCommentForm: React.FC = () => { return ( -
+
-
- - - - -
- -

- Name is required -

+ {touched.name && newComment.name === '' && ( + <> + + + +

+ Name is required +

+ + )}
-
- - - - -
- -

- Email is required -

+ {touched.email && newComment.email === '' && ( + <> + + + +

+ Email is required +

+ + )}
-