From cbfc32daa13958dc3b159bc14cb900f0159c0828 Mon Sep 17 00:00:00 2001 From: denispan <6231990@gmail.com> Date: Mon, 8 Apr 2024 10:10:01 +0200 Subject: [PATCH] =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=20=D0=B8=20?= =?UTF-8?q?=D1=84=D0=B0=D0=B2=D0=BE=D1=80=D0=B8=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../comments-list/comments-list.tsx | 4 +- .../favorite-button/favorite-button.tsx | 26 ++++-- src/components/form-review/const.ts | 5 ++ src/components/form-review/form-review.tsx | 80 +++++++++++++------ src/components/header/header.tsx | 2 +- src/components/map/map.tsx | 15 +++- src/components/offers-list/offers-list.tsx | 17 +++- src/components/rating-star/rating-star.tsx | 8 +- src/components/rating/rating.tsx | 5 +- src/const.ts | 5 -- src/pages/main/main.tsx | 8 +- src/pages/offer/offer.tsx | 26 +++--- src/store/slices/comments.ts | 12 ++- src/utils/common.ts | 2 +- src/utils/sort.ts | 5 ++ 15 files changed, 151 insertions(+), 69 deletions(-) create mode 100644 src/components/form-review/const.ts diff --git a/src/components/comments-list/comments-list.tsx b/src/components/comments-list/comments-list.tsx index 9d3809a..89fad6e 100644 --- a/src/components/comments-list/comments-list.tsx +++ b/src/components/comments-list/comments-list.tsx @@ -8,10 +8,12 @@ interface CommentsListProps { offerId: OfferFullInfo['id']; } +const MAX_COUNT_COMMENTS = 10; + function CommentsList ({offerId}: CommentsListProps) { const {fetchComments} = useActionCreators(commentsActions); const postCommentStatus = useAppSelector(commentsSelectors.statusPostRequest); - const comments = useAppSelector(commentsSelectors.comments); + const comments = useAppSelector(commentsSelectors.sortedComments).slice(0, MAX_COUNT_COMMENTS); const commentsCount = comments.length; useEffect(() => { diff --git a/src/components/favorite-button/favorite-button.tsx b/src/components/favorite-button/favorite-button.tsx index 73508b7..2d5dfbf 100644 --- a/src/components/favorite-button/favorite-button.tsx +++ b/src/components/favorite-button/favorite-button.tsx @@ -3,8 +3,10 @@ import {OfferShortInfo} from '../../types/offer.ts'; import {useActionCreators, useAppSelector} from '../../hooks/store.ts'; import {favoritesActions, favoritesSelectors} from '../../store/slices/favorites.ts'; import {useState} from 'react'; -import {RequestStatus} from '../../const.ts'; +import {AppRoute, AuthStatus, RequestStatus} from '../../const.ts'; import {toast} from 'react-toastify'; +import {useNavigate} from 'react-router-dom'; +import {userSelectors} from '../../store/slices/user.ts'; interface FavoriteButtonProps { componentType: 'place-card' | 'offer'; @@ -27,12 +29,24 @@ function FavoriteButton({componentType, isFavorite, offerId}: FavoriteButtonProp const [isFavoriteCurrent, setIsFavoriteCurrent] = useState(isFavorite); const {toggleFavorite} = useActionCreators(favoritesActions); const statusToggleFavorite = useAppSelector(favoritesSelectors.statusToggleFavorite); + const authStatus = useAppSelector(userSelectors.authStatus); + const navigate = useNavigate(); + + const isAuth = authStatus === AuthStatus.Auth; const onClickHandler = () => { - toast.promise(toggleFavorite({status: Number(!isFavoriteCurrent) as 0 | 1, offerId}) - .unwrap() - .then(() => setIsFavoriteCurrent(!isFavoriteCurrent)), { - pending: 'Запрос отправляется', + if (!isAuth) { + navigate(AppRoute.Login); + } + + toast.promise(toggleFavorite({status: Number(!isFavoriteCurrent) as 0 | 1, offerId}).unwrap(), { + pending: 'Sending request', + success: { + render() { + setIsFavoriteCurrent(!isFavoriteCurrent); + return 'Success'; + } + }, }); }; @@ -41,7 +55,7 @@ function FavoriteButton({componentType, isFavorite, offerId}: FavoriteButtonProp className={ classNames( `${componentType}__bookmark-button button`, - isFavoriteCurrent && `${componentType}__bookmark-button--active`) + isFavoriteCurrent && isAuth && `${componentType}__bookmark-button--active`) } type="button" onClick={onClickHandler} diff --git a/src/components/form-review/const.ts b/src/components/form-review/const.ts new file mode 100644 index 0000000..13dc888 --- /dev/null +++ b/src/components/form-review/const.ts @@ -0,0 +1,5 @@ +const MIN_LENGTH_COMMENT = 50; +const MAX_LENGTH_COMMENT = 300; +const MIN_STARS_COMMENT = 1; + +export {MAX_LENGTH_COMMENT, MIN_STARS_COMMENT, MIN_LENGTH_COMMENT}; diff --git a/src/components/form-review/form-review.tsx b/src/components/form-review/form-review.tsx index 3080723..e8b30cc 100644 --- a/src/components/form-review/form-review.tsx +++ b/src/components/form-review/form-review.tsx @@ -1,45 +1,75 @@ -import {MIN_LENGTH_COMMENT, MIN_STARS_COMMENT, RATING_STARS} from '../../const.ts'; -import {StarTitle, StarValue} from '../rating-star/rating-star.tsx'; -import RatingStar from '../rating-star/rating-star.tsx'; -import {FormEvent, useRef, useState} from 'react'; +import {RATING_STARS} from '../../const.ts'; +import RatingStar, {StarTitle} from '../rating-star/rating-star.tsx'; +import {FormEvent, useState} from 'react'; import {useActionCreators} from '../../hooks/store.ts'; import {commentsActions} from '../../store/slices/comments.ts'; import {OfferFullInfo} from '../../types/offer.ts'; +import {MAX_LENGTH_COMMENT, MIN_LENGTH_COMMENT} from './const.ts'; +import {toast} from 'react-toastify'; type FormReviewProps = { offerId: OfferFullInfo['id']; }; -type InitialForm = { - comment: string; - rating: StarValue; +type Form = HTMLFormElement & { + rating: RadioNodeList; + review: HTMLTextAreaElement; }; -const INITIAL_FORM_VALUE: InitialForm = { - comment: '', - rating: RATING_STARS['unknown'], -}; +const verifyForm = (comment: string, rating: string) => + comment.length <= MIN_LENGTH_COMMENT || comment.length > MAX_LENGTH_COMMENT || Number(rating) === RATING_STARS.unknown; function FormReview({offerId}: FormReviewProps) { - const [textAreaValue, setTextAreaValue] = useState(INITIAL_FORM_VALUE.comment); - const [ratingStar, setRatingStar] = useState(INITIAL_FORM_VALUE.rating); + const [isSubmitDisabled, setIsSubmitDisabled] = useState(true); + const [isFormDisabled, setIsFormDisabled] = useState(false); const {postComment} = useActionCreators(commentsActions); - const formRef = useRef(null); + + const onChangeForm = (evt: FormEvent) => { + const form = evt.currentTarget as Form; + const rating = form.rating.value; + const comment = form.review.value; + setIsSubmitDisabled(verifyForm(comment, rating)); + }; const onFormSubmit = (evt: FormEvent) => { evt.preventDefault(); - postComment({offerId, body: {comment: textAreaValue, rating: ratingStar}}) - .unwrap() - .then(() => { - setTextAreaValue(INITIAL_FORM_VALUE.comment); - setRatingStar(INITIAL_FORM_VALUE.rating); - }); + const form = evt.currentTarget as Form; + + const clearForm = () => { + form.reset(); + setIsSubmitDisabled(true); + setIsFormDisabled(false); + }; + + const commentToSend = { + offerId, + body: { + comment: form.review.value, + rating: Number(form.rating.value), + }, + }; + setIsFormDisabled(true); + toast.promise(postComment(commentToSend).unwrap(), { + pending: 'Sending comment', + success: { + render() { + clearForm(); + return 'Comment sent'; + } + }, + error: { + render() { + setIsFormDisabled(false); + return 'Failed to send comment'; + } + } + }); }; return (
onFormSubmit(evt)} + onChange={(evt) => onChangeForm(evt)} className="reviews__form form" action="#" method="post" @@ -49,21 +79,19 @@ function FormReview({offerId}: FormReviewProps) { {Object.entries(RATING_STARS).slice(1).map(([starTitle, starValue]) => ( ) )}