Repository: htmlacademy-univer-javascript-3/2579201-six-cities-5
Pull request #6: Больше подробностей (часть 2)
Author: login: skyfxllen
Created: 2025-04-01T14:01:49Z | Merged: 2025-04-02T08:56:19Z



---
:mortar_board: [Больше подробностей (часть 2)](https://up.htmlacademy.ru/univer-js3/5/user/2579201/tasks/7)


Diff:
diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx
index 10a1fbe..6613c54 100644
--- a/src/components/App/App.tsx
+++ b/src/components/App/App.tsx
@@ -8,11 +8,13 @@ import { PrivateRoute } from '../PrivateRoute/PrivateRoute';
 import { AppRoute } from '../../const';
 import { OfferType } from '../../types/offers';
 import { FavoritesByCity } from '../../types/favorites';
+import { Review } from '../../types/review';
 type AppProps = {
   offers: OfferType[];
+  reviews: Review[];
 }
 
-const App = ({ offers } : AppProps) : JSX.Element => {
+const App = ({ offers, reviews } : AppProps) : JSX.Element => {
   function getFavoritesByCity(offersList: OfferType[]) {
     return offersList
       .filter((offer) => offer.isFavorite)
@@ -46,7 +48,7 @@ const App = ({ offers } : AppProps) : JSX.Element => {
         />
         <Route
           path={`${AppRoute.Offer}:id`}
-          element={<Offer />}
+          element={<Offer reviews={reviews}/>}
         />
         <Route
           path='*'
diff --git a/src/components/CardRating/CardRating.tsx b/src/components/CardRating/CardRating.tsx
deleted file mode 100644
index b1a53dc..0000000
--- a/src/components/CardRating/CardRating.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-type CardRatingProps = {
-  rating: number;
-}
-
-const CardRating = ({rating}: CardRatingProps) => {
-  const ratingPercent = `${(rating / 5) * 100 }%`;
-  return (
-    <div className="place-card__rating rating">
-      <div className="place-card__stars rating__stars">
-        <span style={{ width: ratingPercent }}></span>
-        <span className="visually-hidden">Rating</span>
-      </div>
-    </div>
-  );
-};
-
-
-export {CardRating};
-
diff --git a/src/components/OfferCard/OfferCard.tsx b/src/components/OfferCard/OfferCard.tsx
index 9c5f54b..ad2dfa8 100644
--- a/src/components/OfferCard/OfferCard.tsx
+++ b/src/components/OfferCard/OfferCard.tsx
@@ -1,13 +1,13 @@
 import { Link } from 'react-router-dom';
 import { OfferType } from '../../types/offers';
 import { AppRoute } from '../../const';
-import { CardRating } from '../CardRating/CardRating';
+import { Rating } from '../Rating/Rating';
 
 type OfferCardType ={
   offer: OfferType;
   onMouseEnter: () => void;
   onMouseLeave: () => void;
-  pageBlock: 'favorites' | 'cities';
+  pageBlock: 'favorites' | 'cities' | 'near-places';
 }
 
 const OfferCard = ({offer, pageBlock, onMouseEnter, onMouseLeave,} : OfferCardType): JSX.Element => {
@@ -42,7 +42,7 @@ const OfferCard = ({offer, pageBlock, onMouseEnter, onMouseLeave,} : OfferCardTy
             <span className="visually-hidden">To bookmarks</span>
           </button>
         </div>
-        <CardRating rating={rating} />
+        <Rating rating={rating} pageBlock='place-card'/>
         <h2 className="place-card__name">
           <Link to={`${AppRoute.Offer}${offer.id}`}>{title}</Link>
         </h2>
diff --git a/src/components/OffersList/OffersList.tsx b/src/components/OffersList/OffersList.tsx
index 0a0c1c1..436f13b 100644
--- a/src/components/OffersList/OffersList.tsx
+++ b/src/components/OffersList/OffersList.tsx
@@ -4,7 +4,7 @@ import { OfferCard } from '../OfferCard/OfferCard';
 
 type OffersListProps = {
   offers: OfferType[];
-  pageBlock: 'favorites' | 'cities';
+  pageBlock: 'favorites' | 'cities' | 'near-places';
 }
 
 const OffersList = ({offers, pageBlock}: OffersListProps) =>{
diff --git a/src/components/Rating/Rating.tsx b/src/components/Rating/Rating.tsx
new file mode 100644
index 0000000..0d2b3ce
--- /dev/null
+++ b/src/components/Rating/Rating.tsx
@@ -0,0 +1,21 @@
+type RatingProps = {
+  rating: number;
+  pageBlock: string;
+}
+
+const Rating = ({rating, pageBlock}: RatingProps) => {
+  const ratingPercent = `${(rating / 5) * 100 }%`;
+  return (
+    <div className={`${pageBlock}__rating rating`}>
+      <div className={`${pageBlock}__stars rating__stars`}>
+        <span style={{ width: ratingPercent }}></span>
+        <span className="visually-hidden">Rating</span>
+      </div>
+      {pageBlock === 'offer' && <span className={`${pageBlock}__rating-value rating__value`}>{rating}</span>}
+    </div>
+  );
+};
+
+
+export {Rating};
+
diff --git a/src/components/ReviewItem/ReviewItem.tsx b/src/components/ReviewItem/ReviewItem.tsx
new file mode 100644
index 0000000..5037772
--- /dev/null
+++ b/src/components/ReviewItem/ReviewItem.tsx
@@ -0,0 +1,33 @@
+import { Review } from '../../types/review';
+import { Rating } from '../Rating/Rating';
+import { ReviewTime } from './components/ReviewTime/ReviewTime';
+
+type Props = {
+  review: Review;
+}
+
+const ReviewItem = ({review}: Props) => {
+  const {user, comment, rating, date} = review;
+  const {name, avatarUrl} = user;
+  return (
+    <li className="reviews__item">
+      <div className="reviews__user user">
+        <div className="reviews__avatar-wrapper user__avatar-wrapper">
+          <img className="reviews__avatar user__avatar" src={avatarUrl} width="54" height="54" alt="Reviews avatar" />
+        </div>
+        <span className="reviews__user-name">
+          {name}
+        </span>
+      </div>
+      <div className="reviews__info">
+        <Rating pageBlock='reviews' rating={rating}/>
+        <p className="reviews__text">
+          {comment}
+        </p>
+        <ReviewTime date={date}/>
+      </div>
+    </li>
+  );
+};
+
+export {ReviewItem};
diff --git a/src/components/ReviewItem/components/ReviewTime/ReviewTime.tsx b/src/components/ReviewItem/components/ReviewTime/ReviewTime.tsx
new file mode 100644
index 0000000..d7a5656
--- /dev/null
+++ b/src/components/ReviewItem/components/ReviewTime/ReviewTime.tsx
@@ -0,0 +1,16 @@
+type ReviewTimeProps = {
+  date: string;
+}
+
+const ReviewTime = ({date}: ReviewTimeProps) => {
+  function formatReviewDate(stringDate: string) {
+    const newDate = new Date(stringDate);
+    return newDate.toLocaleDateString('en-US', { month: 'long', year: 'numeric' });
+  }
+  const dateTime = date.split('T')[0];
+  return (
+    <time className="reviews__time" dateTime={dateTime} >{formatReviewDate(date)}</time>
+  );
+};
+
+export {ReviewTime};
diff --git a/src/components/ReviewList/ReviewList.tsx b/src/components/ReviewList/ReviewList.tsx
new file mode 100644
index 0000000..4b9d0f9
--- /dev/null
+++ b/src/components/ReviewList/ReviewList.tsx
@@ -0,0 +1,13 @@
+import { Review } from '../../types/review';
+import { ReviewItem } from '../ReviewItem/ReviewItem';
+
+type ReviewListProps = {
+  reviewsList: Review[];
+}
+
+const ReviewList = ({reviewsList}: ReviewListProps) => (
+  <ul className="reviews__list">
+    {reviewsList.map((review) => <ReviewItem review={review} key={review.id}/>)}
+  </ul>);
+
+export {ReviewList};
diff --git a/src/components/ReviewsForm/ReviewsForm.tsx b/src/components/ReviewsForm/ReviewsForm.tsx
index a198fd1..e491788 100644
--- a/src/components/ReviewsForm/ReviewsForm.tsx
+++ b/src/components/ReviewsForm/ReviewsForm.tsx
@@ -7,11 +7,11 @@ const ReviewsForm = () => {
   const [rating, setRating] = useState<RatingValue | null>(null);
 
   const scores: Record<RatingValue, string> = {
-    '5' : 'perfect',
-    '4' : 'good',
-    '3' : 'not bad',
-    '2' : 'badly',
-    '1' : 'terribly',
+    5 : 'perfect',
+    4 : 'good',
+    3 : 'not bad',
+    2 : 'badly',
+    1 : 'terribly',
   };
 
   function handleCommentChange(event: ChangeEvent<HTMLTextAreaElement>){
@@ -29,7 +29,7 @@ const ReviewsForm = () => {
       <label className="reviews__label form__label" htmlFor="review">Your review</label>
       <div className="reviews__rating-form form__rating">
         {Object.entries(scores).reverse().map(([score, title]) =>(
-          <RatingStar key={score} score={score as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
+          <RatingStar key={score} score={Number(score)} rating={Number(rating)} title={title} onRatingChange={handleRatingChange}/>
         ))}
       </div>
       <textarea className="reviews__textarea form__textarea" id="review" name="review"
diff --git a/src/index.tsx b/src/index.tsx
index 27b42e0..ad9971f 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -2,6 +2,7 @@ import React from 'react';
 import ReactDOM from 'react-dom/client';
 import { App } from './components/App/App';
 import { offers } from './mocks/offers';
+import { reviews } from './mocks/reviews';
 
 const root = ReactDOM.createRoot(
   document.getElementById('root') as HTMLElement
@@ -9,6 +10,6 @@ const root = ReactDOM.createRoot(
 
 root.render(
   <React.StrictMode>
-    <App offers={offers}/>
+    <App offers={offers} reviews={reviews}/>
   </React.StrictMode>
 );
diff --git a/src/mocks/reviews.ts b/src/mocks/reviews.ts
new file mode 100644
index 0000000..7dcf710
--- /dev/null
+++ b/src/mocks/reviews.ts
@@ -0,0 +1,37 @@
+import { Review } from '../types/review';
+
+export const reviews: Review[] = [
+  {
+    'id': '27936940-88d9-4bb1-8777-3a91a6e045f5',
+    'comment': 'We loved it so much, the house, the veiw, the location just great.. Highly reccomend :)',
+    'date': '2025-03-07T21:00:01.000Z',
+    'rating': 1,
+    'user': {
+      'name': 'Jack',
+      'avatarUrl': 'https://14.design.htmlacademy.pro/static/avatar/1.jpg',
+      'isPro': true
+    }
+  },
+  {
+    'id': 'df9ef767-a983-4d9f-ac1e-d48791845f0e',
+    'comment': 'Bathed in the nature. Completely unplugged. Unforgettable.',
+    'date': '2025-03-05T21:00:01.000Z',
+    'rating': 2,
+    'user': {
+      'name': 'Zak',
+      'avatarUrl': 'https://14.design.htmlacademy.pro/static/avatar/3.jpg',
+      'isPro': false
+    }
+  },
+  {
+    'id': '7e9bd77c-98e9-447e-b1f1-55a627a461a4',
+    'comment': 'We loved it so much, the house, the veiw, the location just great.. Highly reccomend :)',
+    'date': '2025-03-05T21:00:01.000Z',
+    'rating': 4,
+    'user': {
+      'name': 'Corey',
+      'avatarUrl': 'https://14.design.htmlacademy.pro/static/avatar/1.jpg',
+      'isPro': false
+    }
+  }
+];
diff --git a/src/pages/Offer/Offer.tsx b/src/pages/Offer/Offer.tsx
index 11f5cad..b2f7f8b 100644
--- a/src/pages/Offer/Offer.tsx
+++ b/src/pages/Offer/Offer.tsx
@@ -1,294 +1,184 @@
+import { Map } from '../../components/Map/Map';
+import { OffersList } from '../../components/OffersList/OffersList';
+import { Rating } from '../../components/Rating/Rating';
+import { ReviewList } from '../../components/ReviewList/ReviewList';
 import { ReviewsForm } from '../../components/ReviewsForm/ReviewsForm';
+import { usePoints } from '../../hooks/usePoints';
+import { cities } from '../../mocks/cities';
+import { offers } from '../../mocks/offers';
+import { Review } from '../../types/review';
 
-const Offer = () : JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <div className="header__left">
-            <a className="header__logo-link" href="main.html">
-              <img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41" />
-            </a>
-          </div>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <a className="header__nav-link header__nav-link--profile" href="#">
-                  <div className="header__avatar-wrapper user__avatar-wrapper">
-                  </div>
-                  <span className="header__user-name user__name">Oliver.conner@gmail.com</span>
-                  <span className="header__favorite-count">3</span>
-                </a>
-              </li>
-              <li className="header__nav-item">
-                <a className="header__nav-link" href="#">
-                  <span className="header__signout">Sign out</span>
-                </a>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
+type OfferProps = {
+  reviews: Review[];
+}
 
-    <main className="page__main page__main--offer">
-      <section className="offer">
-        <div className="offer__gallery-container container">
-          <div className="offer__gallery">
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/room.jpg" alt="Photo studio" />
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio" />
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-02.jpg" alt="Photo studio" />
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-03.jpg" alt="Photo studio" />
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/studio-01.jpg" alt="Photo studio" />
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio" />
+const Offer = ({reviews} : OfferProps) : JSX.Element => {
+  const nearbiestOffers = offers.slice(0,3);
+  const nearbiestPoints = usePoints(nearbiestOffers);
+  return(
+    <div className="page">
+      <header className="header">
+        <div className="container">
+          <div className="header__wrapper">
+            <div className="header__left">
+              <a className="header__logo-link" href="main.html">
+                <img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41" />
+              </a>
             </div>
+            <nav className="header__nav">
+              <ul className="header__nav-list">
+                <li className="header__nav-item user">
+                  <a className="header__nav-link header__nav-link--profile" href="#">
+                    <div className="header__avatar-wrapper user__avatar-wrapper">
+                    </div>
+                    <span className="header__user-name user__name">Oliver.conner@gmail.com</span>
+                    <span className="header__favorite-count">3</span>
+                  </a>
+                </li>
+                <li className="header__nav-item">
+                  <a className="header__nav-link" href="#">
+                    <span className="header__signout">Sign out</span>
+                  </a>
+                </li>
+              </ul>
+            </nav>
           </div>
         </div>
-        <div className="offer__container container">
-          <div className="offer__wrapper">
-            <div className="offer__mark">
-              <span>Premium</span>
+      </header>
+
+      <main className="page__main page__main--offer">
+        <section className="offer">
+          <div className="offer__gallery-container container">
+            <div className="offer__gallery">
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/room.jpg" alt="Photo studio" />
+              </div>
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio" />
+              </div>
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/apartment-02.jpg" alt="Photo studio" />
+              </div>
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/apartment-03.jpg" alt="Photo studio" />
+              </div>
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/studio-01.jpg" alt="Photo studio" />
+              </div>
+              <div className="offer__image-wrapper">
+                <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio" />
+              </div>
             </div>
-            <div className="offer__name-wrapper">
-              <h1 className="offer__name">
+          </div>
+          <div className="offer__container container">
+            <div className="offer__wrapper">
+              <div className="offer__mark">
+                <span>Premium</span>
+              </div>
+              <div className="offer__name-wrapper">
+                <h1 className="offer__name">
                   Beautiful &amp; luxurious studio at great location
-              </h1>
-              <button className="offer__bookmark-button button" type="button">
-                <svg className="offer__bookmark-icon" width="31" height="33">
-                  <use xlinkHref="#icon-bookmark"></use>
-                </svg>
-                <span className="visually-hidden">To bookmarks</span>
-              </button>
-            </div>
-            <div className="offer__rating rating">
-              <div className="offer__stars rating__stars">
-                <span style={{width: '80%'}}></span>
-                <span className="visually-hidden">Rating</span>
+                </h1>
+                <button className="offer__bookmark-button button" type="button">
+                  <svg className="offer__bookmark-icon" width="31" height="33">
+                    <use xlinkHref="#icon-bookmark"></use>
+                  </svg>
+                  <span className="visually-hidden">To bookmarks</span>
+                </button>
               </div>
-              <span className="offer__rating-value rating__value">4.8</span>
-            </div>
-            <ul className="offer__features">
-              <li className="offer__feature offer__feature--entire">
+              <Rating rating={4} pageBlock='offer'/>
+              <ul className="offer__features">
+                <li className="offer__feature offer__feature--entire">
                   Apartment
-              </li>
-              <li className="offer__feature offer__feature--bedrooms">
+                </li>
+                <li className="offer__feature offer__feature--bedrooms">
                   3 Bedrooms
-              </li>
-              <li className="offer__feature offer__feature--adults">
+                </li>
+                <li className="offer__feature offer__feature--adults">
                   Max 4 adults
-              </li>
-            </ul>
-            <div className="offer__price">
-              <b className="offer__price-value">&euro;120</b>
-              <span className="offer__price-text">&nbsp;night</span>
-            </div>
-            <div className="offer__inside">
-              <h2 className="offer__inside-title">What&apos;s inside</h2>
-              <ul className="offer__inside-list">
-                <li className="offer__inside-item">
-                    Wi-Fi
                 </li>
-                <li className="offer__inside-item">
+              </ul>
+              <div className="offer__price">
+                <b className="offer__price-value">&euro;120</b>
+                <span className="offer__price-text">&nbsp;night</span>
+              </div>
+              <div className="offer__inside">
+                <h2 className="offer__inside-title">What&apos;s inside</h2>
+                <ul className="offer__inside-list">
+                  <li className="offer__inside-item">
+                    Wi-Fi
+                  </li>
+                  <li className="offer__inside-item">
                     Washing machine
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Towels
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Heating
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Coffee machine
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Baby seat
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Kitchen
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Dishwasher
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Cabel TV
-                </li>
-                <li className="offer__inside-item">
+                  </li>
+                  <li className="offer__inside-item">
                     Fridge
-                </li>
-              </ul>
-            </div>
-            <div className="offer__host">
-              <h2 className="offer__host-title">Meet the host</h2>
-              <div className="offer__host-user user">
-                <div className="offer__avatar-wrapper offer__avatar-wrapper--pro user__avatar-wrapper">
-                  <img className="offer__avatar user__avatar" src="img/avatar-angelina.jpg" width="74" height="74" alt="Host avatar" />
-                </div>
-                <span className="offer__user-name">
+                  </li>
+                </ul>
+              </div>
+              <div className="offer__host">
+                <h2 className="offer__host-title">Meet the host</h2>
+                <div className="offer__host-user user">
+                  <div className="offer__avatar-wrapper offer__avatar-wrapper--pro user__avatar-wrapper">
+                    <img className="offer__avatar user__avatar" src="img/avatar-angelina.jpg" width="74" height="74" alt="Host avatar" />
+                  </div>
+                  <span className="offer__user-name">
                     Angelina
-                </span>
-                <span className="offer__user-status">
+                  </span>
+                  <span className="offer__user-status">
                     Pro
-                </span>
-              </div>
-              <div className="offer__description">
-                <p className="offer__text">
+                  </span>
+                </div>
+                <div className="offer__description">
+                  <p className="offer__text">
                     A quiet cozy and picturesque that hides behind a a river by the unique lightness of Amsterdam. The building is green and from 18th century.
-                </p>
-                <p className="offer__text">
+                  </p>
+                  <p className="offer__text">
                     An independent House, strategically located between Rembrand Square and National Opera, but where the bustle of the city comes to rest in this alley flowery and colorful.
-                </p>
-              </div>
-            </div>
-            <section className="offer__reviews reviews">
-              <h2 className="reviews__title">Reviews &middot; <span className="reviews__amount">1</span></h2>
-              <ul className="reviews__list">
-                <li className="reviews__item">
-                  <div className="reviews__user user">
-                    <div className="reviews__avatar-wrapper user__avatar-wrapper">
-                      <img className="reviews__avatar user__avatar" src="img/avatar-max.jpg" width="54" height="54" alt="Reviews avatar" />
-                    </div>
-                    <span className="reviews__user-name">
-                        Max
-                    </span>
-                  </div>
-                  <div className="reviews__info">
-                    <div className="reviews__rating rating">
-                      <div className="reviews__stars rating__stars">
-                        <span style={{width: '80%'}}></span>
-                        <span className="visually-hidden">Rating</span>
-                      </div>
-                    </div>
-                    <p className="reviews__text">
-                        A quiet cozy and picturesque that hides behind a a river by the unique lightness of Amsterdam. The building is green and from 18th century.
-                    </p>
-                    <time className="reviews__time" dateTime="2019-04-24">April 2019</time>
-                  </div>
-                </li>
-              </ul>
-              <ReviewsForm />
-            </section>
-          </div>
-        </div>
-        <section className="offer__map map"></section>
-      </section>
-      <div className="container">
-        <section className="near-places places">
-          <h2 className="near-places__title">Other places in the neighbourhood</h2>
-          <div className="near-places__list places__list">
-            <article className="near-places__card place-card">
-              <div className="near-places__image-wrapper place-card__image-wrapper">
-                <a href="#">
-                  <img className="place-card__image" src="img/room.jpg" width="260" height="200" alt="Place image" />
-                </a>
-              </div>
-              <div className="place-card__info">
-                <div className="place-card__price-wrapper">
-                  <div className="place-card__price">
-                    <b className="place-card__price-value">&euro;80</b>
-                    <span className="place-card__price-text">&#47;&nbsp;night</span>
-                  </div>
-                  <button className="place-card__bookmark-button place-card__bookmark-button--active button" type="button">
-                    <svg className="place-card__bookmark-icon" width="18" height="19">
-                      <use xlinkHref="#icon-bookmark"></use>
-                    </svg>
-                    <span className="visually-hidden">In bookmarks</span>
-                  </button>
-                </div>
-                <div className="place-card__rating rating">
-                  <div className="place-card__stars rating__stars">
-                    <span style={{width: '80%'}}></span>
-                    <span className="visually-hidden">Rating</span>
-                  </div>
-                </div>
-                <h2 className="place-card__name">
-                  <a href="#">Wood and stone place</a>
-                </h2>
-                <p className="place-card__type">Room</p>
-              </div>
-            </article>
-
-            <article className="near-places__card place-card">
-              <div className="near-places__image-wrapper place-card__image-wrapper">
-                <a href="#">
-                  <img className="place-card__image" src="img/apartment-02.jpg" width="260" height="200" alt="Place image" />
-                </a>
-              </div>
-              <div className="place-card__info">
-                <div className="place-card__price-wrapper">
-                  <div className="place-card__price">
-                    <b className="place-card__price-value">&euro;132</b>
-                    <span className="place-card__price-text">&#47;&nbsp;night</span>
-                  </div>
-                  <button className="place-card__bookmark-button button" type="button">
-                    <svg className="place-card__bookmark-icon" width="18" height="19">
-                      <use xlinkHref="#icon-bookmark"></use>
-                    </svg>
-                    <span className="visually-hidden">To bookmarks</span>
-                  </button>
-                </div>
-                <div className="place-card__rating rating">
-                  <div className="place-card__stars rating__stars">
-                    <span style={{width: '80%'}}></span>
-                    <span className="visually-hidden">Rating</span>
-                  </div>
-                </div>
-                <h2 className="place-card__name">
-                  <a href="#">Canal View Prinsengracht</a>
-                </h2>
-                <p className="place-card__type">Apartment</p>
-              </div>
-            </article>
-
-            <article className="near-places__card place-card">
-              <div className="place-card__mark">
-                <span>Premium</span>
-              </div>
-              <div className="near-places__image-wrapper place-card__image-wrapper">
-                <a href="#">
-                  <img className="place-card__image" src="img/apartment-03.jpg" width="260" height="200" alt="Place image" />
-                </a>
-              </div>
-              <div className="place-card__info">
-                <div className="place-card__price-wrapper">
-                  <div className="place-card__price">
-                    <b className="place-card__price-value">&euro;180</b>
-                    <span className="place-card__price-text">&#47;&nbsp;night</span>
-                  </div>
-                  <button className="place-card__bookmark-button button" type="button">
-                    <svg className="place-card__bookmark-icon" width="18" height="19">
-                      <use xlinkHref="#icon-bookmark"></use>
-                    </svg>
-                    <span className="visually-hidden">To bookmarks</span>
-                  </button>
+                  </p>
                 </div>
-                <div className="place-card__rating rating">
-                  <div className="place-card__stars rating__stars">
-                    <span style={{width: '100%'}}></span>
-                    <span className="visually-hidden">Rating</span>
-                  </div>
-                </div>
-                <h2 className="place-card__name">
-                  <a href="#">Nice, cozy, warm big bed apartment</a>
-                </h2>
-                <p className="place-card__type">Apartment</p>
               </div>
-            </article>
+              <section className="offer__reviews reviews">
+                <h2 className="reviews__title">Reviews &middot; <span className="reviews__amount">{reviews.length}</span></h2>
+                <ReviewList reviewsList={reviews}/>
+                <ReviewsForm />
+              </section>
+            </div>
           </div>
+          <Map pageBlock='offer' city={cities.Amsterdam} points={nearbiestPoints}/>
         </section>
-      </div>
-    </main>
-  </div>
-);
+        <div className="container">
+          <section className="near-places places">
+            <h2 className="near-places__title">Other places in the neighbourhood</h2>
+            <div className="near-places__list places__list">
+              <OffersList offers={nearbiestOffers} pageBlock='near-places'/>
+            </div>
+          </section>
+        </div>
+      </main>
+    </div>
+  );
+};
 
 export { Offer };
diff --git a/src/types/offers.ts b/src/types/offers.ts
index e3687c7..e7d5df5 100644
--- a/src/types/offers.ts
+++ b/src/types/offers.ts
@@ -1,3 +1,5 @@
+import { RatingValue } from './rating';
+
 export type Location = {
   latitude: number;
   longitude: number;
@@ -29,6 +31,6 @@ export type OfferType = {
   location: Location;
   isFavorite: boolean;
   isPremium: boolean;
-  rating: number;
+  rating: RatingValue;
   previewImage: string;
   }
diff --git a/src/types/rating.ts b/src/types/rating.ts
index 9ece77f..a4a7116 100644
--- a/src/types/rating.ts
+++ b/src/types/rating.ts
@@ -1 +1 @@
-export type RatingValue = '1' | '2' | '3' | '4' | '5';
+export type RatingValue = number;
diff --git a/src/types/review.tsx b/src/types/review.tsx
new file mode 100644
index 0000000..cefb391
--- /dev/null
+++ b/src/types/review.tsx
@@ -0,0 +1,15 @@
+import { RatingValue } from './rating';
+
+export type User ={
+  name: string;
+  avatarUrl: string;
+  isPro: boolean;
+}
+
+export type Review = {
+  id: string;
+  date: string;
+  user: User;
+  comment: string;
+  rating: RatingValue;
+};


Reviews:
user: login: nesen-kontur
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-02T05:51:51Z
user: login: skyfxllen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T07:48:17Z
user: login: skyfxllen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T07:48:21Z
user: login: skyfxllen
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-02T07:48:25Z
user: login: nesen-kontur
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-02T08:45:37Z

Review comments:
diff_hunk: @@ -0,0 +1,37 @@
+import { Review } from '../../types/review';
+import { ReviewTime } from './components/ReviewTime/ReviewTime';
+
+type Props = {
+  review: Review;
+}
+
+const ReviewItem = ({review}: Props) => {
+  const {user, comment, rating, date} = review;
+  const {name, avatarUrl} = user;
+  return (
+    <li className="reviews__item">
+      <div className="reviews__user user">
+        <div className="reviews__avatar-wrapper user__avatar-wrapper">
+          <img className="reviews__avatar user__avatar" src={avatarUrl} width="54" height="54" alt="Reviews avatar" />
+        </div>
+        <span className="reviews__user-name">
+          {name}
+        </span>
+      </div>
+      <div className="reviews__info">
+        <div className="reviews__rating rating">
+          <div className="reviews__stars rating__stars">
path: src/components/ReviewItem/ReviewItem.tsx
user: login: nesen-kontur
body: кажется тут тоже место для компонента рейтинга
created_at: 2025-04-02T05:46:10Z
author_association: NONE
diff_hunk: @@ -29,7 +29,7 @@ const ReviewsForm = () => {
       <label className="reviews__label form__label" htmlFor="review">Your review</label>
       <div className="reviews__rating-form form__rating">
         {Object.entries(scores).reverse().map(([score, title]) =>(
-          <RatingStar key={score} score={score as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
+          <RatingStar key={score} score={Number(score) as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
path: src/components/ReviewsForm/ReviewsForm.tsx
user: login: nesen-kontur
body: пришло время избавиться от каста as
created_at: 2025-04-02T05:47:37Z
author_association: NONE
diff_hunk: @@ -1 +1 @@
-export type RatingValue = '1' | '2' | '3' | '4' | '5';
+export type RatingValue = 1 | 2 | 3 | 4 | 5;
path: src/types/rating.ts
user: login: nesen-kontur
body: можешь пока просто оставить number, могу для таких случаев порекомендовать статейку про брендированные типы https://www.learningtypescript.com/articles/branded-types
created_at: 2025-04-02T05:50:57Z
author_association: NONE
diff_hunk: @@ -0,0 +1,37 @@
+import { Review } from '../../types/review';
+import { ReviewTime } from './components/ReviewTime/ReviewTime';
+
+type Props = {
+  review: Review;
+}
+
+const ReviewItem = ({review}: Props) => {
+  const {user, comment, rating, date} = review;
+  const {name, avatarUrl} = user;
+  return (
+    <li className="reviews__item">
+      <div className="reviews__user user">
+        <div className="reviews__avatar-wrapper user__avatar-wrapper">
+          <img className="reviews__avatar user__avatar" src={avatarUrl} width="54" height="54" alt="Reviews avatar" />
+        </div>
+        <span className="reviews__user-name">
+          {name}
+        </span>
+      </div>
+      <div className="reviews__info">
+        <div className="reviews__rating rating">
+          <div className="reviews__stars rating__stars">
path: src/components/ReviewItem/ReviewItem.tsx
user: login: skyfxllen
body: да, упустил этот момент как-то
created_at: 2025-04-02T07:48:17Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,7 +29,7 @@ const ReviewsForm = () => {
       <label className="reviews__label form__label" htmlFor="review">Your review</label>
       <div className="reviews__rating-form form__rating">
         {Object.entries(scores).reverse().map(([score, title]) =>(
-          <RatingStar key={score} score={score as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
+          <RatingStar key={score} score={Number(score) as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
path: src/components/ReviewsForm/ReviewsForm.tsx
user: login: skyfxllen
body: не очень понял, просто привести к типу number потому что RatingValue теперь number?
created_at: 2025-04-02T07:48:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1 +1 @@
-export type RatingValue = '1' | '2' | '3' | '4' | '5';
+export type RatingValue = 1 | 2 | 3 | 4 | 5;
path: src/types/rating.ts
user: login: skyfxllen
body: Хорошо
created_at: 2025-04-02T07:48:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -29,7 +29,7 @@ const ReviewsForm = () => {
       <label className="reviews__label form__label" htmlFor="review">Your review</label>
       <div className="reviews__rating-form form__rating">
         {Object.entries(scores).reverse().map(([score, title]) =>(
-          <RatingStar key={score} score={score as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
+          <RatingStar key={score} score={Number(score) as RatingValue} rating={rating as RatingValue} title={title} onRatingChange={handleRatingChange}/>
path: src/components/ReviewsForm/ReviewsForm.tsx
user: login: nesen-kontur
body: угу  можно просто использовать тип number
created_at: 2025-04-02T08:45:37Z
author_association: NONE

PR comments:
user: login: github-actions[bot]
created_at: 2025-04-01T14:02:35Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579201-six-cities-5/6/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-02T07:49:20Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579201-six-cities-5/6/)
author_association: NONE