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]) => ( ) )}