diff --git a/src/Pages/login-page/login-page.tsx b/src/Pages/login-page/login-page.tsx index 96cd2f6..933830b 100644 --- a/src/Pages/login-page/login-page.tsx +++ b/src/Pages/login-page/login-page.tsx @@ -45,8 +45,7 @@ export function LoginPage(): React.JSX.Element { name="email" placeholder="Email" onChange={(event) => - setLoginInfo({ ...loginInfo, email: event.target.value }) - } + setLoginInfo({ ...loginInfo, email: event.target.value })} required /> @@ -61,8 +60,7 @@ export function LoginPage(): React.JSX.Element { setLoginInfo({ ...loginInfo, password: event.target.value, - }) - } + })} required /> diff --git a/src/Pages/main-page/main-page.tsx b/src/Pages/main-page/main-page.tsx index a78219c..e3227a1 100644 --- a/src/Pages/main-page/main-page.tsx +++ b/src/Pages/main-page/main-page.tsx @@ -24,7 +24,7 @@ export function MainPage(): React.JSX.Element { : `${pluralizeAndCombine('place', offers.length)} to stay in ${city.name}`; return (
- +
6 cities

Cities

diff --git a/src/Pages/offer-page/offer-page.tsx b/src/Pages/offer-page/offer-page.tsx index e23f346..cc004f3 100644 --- a/src/Pages/offer-page/offer-page.tsx +++ b/src/Pages/offer-page/offer-page.tsx @@ -4,7 +4,7 @@ import { OffersList } from '../../components/offer/offers-list.tsx'; import { Reviews } from '../../components/reviews/reviews.tsx'; import { Map } from '../../components/map/map.tsx'; import React, { useEffect } from 'react'; -import { useParams } from 'react-router-dom'; +import { Navigate, useParams } from 'react-router-dom'; import { OfferInsideItems } from '../../components/offer/offer-inside-items.tsx'; import { OfferHost } from '../../components/offer/offer-host.tsx'; import { capitalize, pluralizeAndCombine } from '../../utils/string-utils.ts'; @@ -15,9 +15,11 @@ import { store, useAppSelector } from '../../store/store.ts'; import { fetchNearbyOffers, fetchOffer, + fetchReviews, setCurrentOffer, } from '../../store/actions.ts'; import { Spinner } from '../../components/spinner/Spinner.tsx'; +import { AppRoutes } from '../../dataTypes/enums/app-routes.ts'; export function OfferPage(): React.JSX.Element { const offerId = useParams().id; @@ -25,12 +27,17 @@ export function OfferPage(): React.JSX.Element { store.dispatch(setCurrentOffer(null)); store.dispatch(fetchOffer(offerId!)); store.dispatch(fetchNearbyOffers(offerId!)); + store.dispatch(fetchReviews(offerId!)); }, [offerId]); const nearbyOffers = useAppSelector((state) => state.nearbyOffers).slice( 0, 3, ); const currentOffer = useAppSelector((state) => state.currentOffer); + const currentReviews = useAppSelector((state) => state.currentReviews); + if (currentOffer === undefined) { + return ; + } return (
@@ -60,7 +67,7 @@ export function OfferPage(): React.JSX.Element {
  • @@ -89,7 +96,7 @@ export function OfferPage(): React.JSX.Element {

- + { setAuthorizationStatus(AuthorizationStatus.Unauthorized), ); } + if (error.response && error.response.status === 404) { + store.dispatch(setCurrentOffer(undefined)); + } throw error; }, ); diff --git a/src/components/offer/offer-card.tsx b/src/components/offer/offer-card.tsx index baed48e..13184bf 100644 --- a/src/components/offer/offer-card.tsx +++ b/src/components/offer/offer-card.tsx @@ -4,6 +4,7 @@ import { AppRoutes } from '../../dataTypes/enums/app-routes.ts'; import cn from 'classnames'; import { Rating } from '../rating.tsx'; import { BookmarkButton } from '../bookmark-button.tsx'; +import { capitalize } from '../../utils/string-utils.ts'; interface PlaceCardProps { id: string; @@ -40,7 +41,7 @@ export function OfferCard({ onMouseLeave={handleMouseLeave} className={cn( 'place-card', - { cities__card: isOnMainPage }, + { 'cities__card': isOnMainPage }, { 'near-places__card': !isOnMainPage }, )} > @@ -82,7 +83,7 @@ export function OfferCard({

{title}

-

{type}

+

{capitalize(type)}

); diff --git a/src/components/offer/offer-gallery.tsx b/src/components/offer/offer-gallery.tsx index a1047be..291b84b 100644 --- a/src/components/offer/offer-gallery.tsx +++ b/src/components/offer/offer-gallery.tsx @@ -10,7 +10,7 @@ export function OfferGallery({ return (
- {imageSources.map((src) => ( + {imageSources.slice(0, 6).map((src) => (
Photo studio
diff --git a/src/components/offer/offer-host.tsx b/src/components/offer/offer-host.tsx index e4c288b..18b0e14 100644 --- a/src/components/offer/offer-host.tsx +++ b/src/components/offer/offer-host.tsx @@ -11,7 +11,17 @@ export function OfferHost({ host }: OfferHostProps): React.JSX.Element { <>

Meet the host

-
+ {host.isPro ? ( +
+ Host avatar +
+ ) : ( Host avatar -
+ )} {getFirstName(host.name)} {host.isPro && Pro}
diff --git a/src/components/rating.tsx b/src/components/rating.tsx index 7db3415..621be8d 100644 --- a/src/components/rating.tsx +++ b/src/components/rating.tsx @@ -3,21 +3,21 @@ import React from 'react'; interface RatingProps { rating: number; usePlace: string; - isInOffer?: boolean; + showRatingValue?: boolean; } export function Rating({ rating, - isInOffer, + showRatingValue, usePlace, }: RatingProps): React.JSX.Element { return (
- + Rating
- {isInOffer && ( + {showRatingValue && ( {rating} )}
diff --git a/src/components/reviews/review-form.tsx b/src/components/reviews/review-form.tsx index e9a25ba..143535a 100644 --- a/src/components/reviews/review-form.tsx +++ b/src/components/reviews/review-form.tsx @@ -1,4 +1,10 @@ import { useState } from 'react'; +import { store, useAppSelector } from '../../store/store.ts'; +import { postReview } from '../../store/actions.ts'; +import { + MAX_COMMENT_LENGTH, + MIN_COMMENT_LENGTH, +} from '../../consts/reviews.ts'; type UserReview = { comment?: string; @@ -7,16 +13,32 @@ type UserReview = { export function ReviewForm(): React.JSX.Element { const [review, setReview] = useState(); + const offerId = useAppSelector((state) => state.currentOffer)!.id; const onRatingChange: React.ChangeEventHandler = ( event, ): void => setReview({ ...review, rating: +event.target.value }); const onCommentChange: React.ChangeEventHandler = ( event, ): void => setReview({ ...review, comment: event.target.value }); + const handleSubmit: React.MouseEventHandler = ( + event, + ): void => { + event.preventDefault(); + store.dispatch( + postReview({ + offerId: offerId, + rating: review?.rating || 5, + comment: review?.comment || '', + }), + ); + }; const isValid = - review?.comment && review?.comment?.length >= 50 && review?.rating; + review?.comment && + review?.comment?.length >= MIN_COMMENT_LENGTH && + review?.comment?.length <= MAX_COMMENT_LENGTH && + review?.rating; return ( -
+ @@ -123,11 +145,20 @@ export function ReviewForm(): React.JSX.Element {

To submit review please make sure to set{' '} rating and describe your stay - with at least 50 characters. + with at least{' '} + + {MIN_COMMENT_LENGTH} characters + {' '} + and no more than{' '} + + {MAX_COMMENT_LENGTH} characters + + .