Repository: htmlacademy-univer-javascript-3/2579369-six-cities-5
Pull request #4: Обратная сторона реальности
Author: login: Suninall
Created: 2025-03-22T10:00:15Z | Merged: 2025-03-26T04:02:52Z



---
:mortar_board: [Обратная сторона реальности](https://up.htmlacademy.ru/univer-js3/5/user/2579369/tasks/5)


Diff:
diff --git a/src/components/app/app.tsx b/src/components/app/app.tsx
index 13ff2ca..90120f2 100644
--- a/src/components/app/app.tsx
+++ b/src/components/app/app.tsx
@@ -10,26 +10,29 @@ import LoginComponent from '../login-component/login-component';
 import OfferPage from '../offer-page/offer-page';
 import ErrorPage from '../errorPage/errorPage';
 import PrivateRoute from '../private-route/private-route';
+import { OffersPreview } from '../../types/offers-preview';
+import { getOfferPath } from '../../utils/common';
+
 
 type AppScreenProps = {
-  cardsCount: number;
   authStatus: AuthorizationStatus;
+  offers: OffersPreview;
 }
 
 
-const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
+const App = ({authStatus, offers}: AppScreenProps): JSX.Element => (
 
   <BrowserRouter>
     <Routes>
       <Route
         path={AppRoute.Main}
-        element={<MainPage cardsCount={cardsCount}/>}
+        element={<MainPage offers={offers}/>}
       />
       <Route
         path={AppRoute.Favorites}
         element ={
           <PrivateRoute isAuthorizate={authStatus === AuthorizationStatus.Auth}>
-            <FavoritesPage/>
+            <FavoritesPage offers = {offers}/>
           </PrivateRoute>
         }
       />
@@ -38,7 +41,7 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
+        path={getOfferPath(':offerId')}
         element ={<OfferPage/>}
       />
       <Route
diff --git a/src/components/card/card.tsx b/src/components/card/card.tsx
index 298db8d..acc7b34 100644
--- a/src/components/card/card.tsx
+++ b/src/components/card/card.tsx
@@ -1,39 +1,61 @@
 import { Link } from 'react-router-dom';
+import { OfferPreview } from '../../types/offers-preview';
+import { getRatingWidth } from '../../utils/cards';
+import { getOfferPath } from '../../utils/common';
 
-const Card = (): JSX.Element => (
-  <article className="cities__card place-card">
-    <div className="place-card__mark">
-      <span>Premium</span>
-    </div>
-    <div className="cities__image-wrapper place-card__image-wrapper">
-      <Link to="#">
-        <img className="place-card__image" src="img/apartment-01.jpg" width="260" height="200" alt="Place image"></img>
-      </Link>
-    </div>
-    <div className="place-card__info">
-      <div className="place-card__price-wrapper">
-        <div className="place-card__price">
-          <b className="place-card__price-value">&euro;120</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>
+
+type CardProps = {
+  offer: OfferPreview;
+  block: string;
+  onCardHover?: (offerId: OfferPreview['id'] | null) => void;
+
+}
+
+const Card = ({offer, block, onCardHover}: CardProps): JSX.Element => {
+
+  const {isPremium, previewImage, id, price, rating, title, type } = offer;
+
+
+  return(
+    <article
+      className={`${block}__card place-card`}
+      onMouseEnter={() => onCardHover?.(id)}
+      onMouseLeave={() => onCardHover?.(null)}
+    >
+      {isPremium && (
+        <div className="place-card__mark">
+          <span>Premium</span>
+        </div>)}
+      <div className={`${block}__image-wrapper place-card__image-wrapper`}>
+        <Link to={getOfferPath(id)}>
+          <img className="place-card__image" src={previewImage} width="260" height="200" alt={title}></img>
+        </Link>
       </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 className="place-card__info">
+        <div className="place-card__price-wrapper">
+          <div className="place-card__price">
+            <b className="place-card__price-value">&euro;{price}</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: getRatingWidth(rating)}}></span>
+            <span className="visually-hidden">Rating</span>
+          </div>
         </div>
+        <h2 className="place-card__name">
+          <Link to={getOfferPath(id)}>{title}</Link>
+        </h2>
+        <p className="place-card__type">{type}</p>
       </div>
-      <h2 className="place-card__name">
-        <Link to="#">Beautiful &amp; luxurious apartment at great location</Link>
-      </h2>
-      <p className="place-card__type">Apartment</p>
-    </div>
-  </article>
-);
+    </article>
+  );
+};
 export default Card;
diff --git a/src/components/cards-list/cards-list.tsx b/src/components/cards-list/cards-list.tsx
new file mode 100644
index 0000000..98600be
--- /dev/null
+++ b/src/components/cards-list/cards-list.tsx
@@ -0,0 +1,22 @@
+import { OfferPreview } from '../../types/offers-preview';
+import Card from '../card/card';
+import { useState } from 'react';
+
+type CardsProps = {
+  offers: OfferPreview[];
+}
+
+const Cards = ({offers}: CardsProps): JSX.Element => {
+  const[activeCard, setActiveCard] = useState<OfferPreview['id'] | null>(null);
+
+  return(
+    <>
+      {offers.map((offer) => (
+        <Card key={offer.id} offer={offer} block="cities" onCardHover={setActiveCard} />
+      ))}
+      {activeCard}
+    </>
+  );
+};
+
+export default Cards;
diff --git a/src/components/favorites-page/favorites-page.tsx b/src/components/favorites-page/favorites-page.tsx
index 64ab6c0..6049954 100644
--- a/src/components/favorites-page/favorites-page.tsx
+++ b/src/components/favorites-page/favorites-page.tsx
@@ -1,167 +1,75 @@
 import { Link } from 'react-router-dom';
 import Logo from '../logo/logo';
+import { OfferPreview } from '../../types/offers-preview';
+import Card from '../card/card';
+import getFavoritiesByCity from '../../utils/favorities-by-city';
+type FavoritiesProps = {
+  offers: OfferPreview[];
+}
 
-const FavoritesPage = (): JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <Logo/>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
-                  <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>
-                </Link>
-              </li>
-              <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
-                  <span className="header__signout">Sign out</span>
-                </Link>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
-
-    <main className="page__main page__main--favorites">
-      <div className="page__favorites-container container">
-        <section className="favorites">
-          <h1 className="favorites__title">Saved listing</h1>
-          <ul className="favorites__list">
-            <li className="favorites__locations-items">
-              <div className="favorites__locations locations locations--current">
-                <div className="locations__item">
-                  <Link className="locations__item-link" to="#">
-                    <span>Amsterdam</span>
-                  </Link>
-                </div>
-              </div>
-              <div className="favorites__places">
-                <article className="favorites__card place-card">
-                  <div className="place-card__mark">
-                    <span>Premium</span>
-                  </div>
-                  <div className="favorites__image-wrapper place-card__image-wrapper">
-                    <Link to="#">
-                      <img className="place-card__image" src="img/apartment-small-03.jpg" width="150" height="110" alt="Place image"></img>
-                    </Link>
-                  </div>
-                  <div className="favorites__card-info 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 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>
+const FavoritesPage = ({offers}: FavoritiesProps): JSX.Element => {
+  const favoritesByCity = getFavoritiesByCity(offers);
+  return (
+    <div className="page">
+      <header className="header">
+        <div className="container">
+          <div className="header__wrapper">
+            <Logo/>
+            <nav className="header__nav">
+              <ul className="header__nav-list">
+                <li className="header__nav-item user">
+                  <Link className="header__nav-link header__nav-link--profile" to="#">
+                    <div className="header__avatar-wrapper user__avatar-wrapper">
                     </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">
-                      <Link to="#">Nice, cozy, warm big bed apartment</Link>
-                    </h2>
-                    <p className="place-card__type">Apartment</p>
-                  </div>
-                </article>
+                    <span className="header__user-name user__name">Oliver.conner@gmail.com</span>
+                    <span className="header__favorite-count">3</span>
+                  </Link>
+                </li>
+                <li className="header__nav-item">
+                  <Link className="header__nav-link" to="/login">
+                    <span className="header__signout">Sign out</span>
+                  </Link>
+                </li>
+              </ul>
+            </nav>
+          </div>
+        </div>
+      </header>
 
-                <article className="favorites__card place-card">
-                  <div className="favorites__image-wrapper place-card__image-wrapper">
-                    <Link to="#">
-                      <img className="place-card__image" src="img/room-small.jpg" width="150" height="110" alt="Place image"></img>
-                    </Link>
-                  </div>
-                  <div className="favorites__card-info 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>
+      <main className="page__main page__main--favorites">
+        <div className="page__favorites-container container">
+          <section className="favorites">
+            <h1 className="favorites__title">Saved listing</h1>
+            <ul className="favorites__list">
+              {Object.entries(favoritesByCity).map(
+                ([city, groupedFavorities]) => (
+                  <li className="favorites__locations-items" key={city}>
+                    <div className="favorites__locations locations locations--current">
+                      <div className="locations__item">
+                        <Link className="locations__item-link" to="#">
+                          <span>{city}</span>
+                        </Link>
                       </div>
                     </div>
-                    <h2 className="place-card__name">
-                      <Link to="#">Wood and stone place</Link>
-                    </h2>
-                    <p className="place-card__type">Room</p>
-                  </div>
-                </article>
-              </div>
-            </li>
+                    <div className="favorites__places">
+                      {groupedFavorities.filter((offer) => offer.isFavorite).map((offer) => (
 
-            <li className="favorites__locations-items">
-              <div className="favorites__locations locations locations--current">
-                <div className="locations__item">
-                  <Link className="locations__item-link" to="#">
-                    <span>Cologne</span>
-                  </Link>
-                </div>
-              </div>
-              <div className="favorites__places">
-                <article className="favorites__card place-card">
-                  <div className="favorites__image-wrapper place-card__image-wrapper">
-                    <Link to="#">
-                      <img className="place-card__image" src="img/apartment-small-04.jpg" width="150" height="110" alt="Place image"></img>
-                    </Link>
-                  </div>
-                  <div className="favorites__card-info 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 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>
+                        <Card offer={offer} key={offer.id} block="favorities"/>
+                      ))}
                     </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">
-                      <Link to="#">White castle</Link>
-                    </h2>
-                    <p className="place-card__type">Apartment</p>
-                  </div>
-                </article>
-              </div>
-            </li>
-          </ul>
-        </section>
-      </div>
-    </main>
-    <footer className="footer container">
-      <Link className="footer__logo-link" to="main.html">
-        <img className="footer__logo" src="img/logo.svg" alt="6 cities logo" width="64" height="33"></img>
-      </Link>
-    </footer>
-  </div>
-);
+                  </li>
+                )
+              )}
+            </ul>
+          </section>
+        </div>
+      </main>
+      <footer className="footer container">
+        <Link className="footer__logo-link" to="main.html">
+          <img className="footer__logo" src="img/logo.svg" alt="6 cities logo" width="64" height="33"></img>
+        </Link>
+      </footer>
+    </div>
+  );
+};
 export default FavoritesPage;
diff --git a/src/components/main-page/main-page.tsx b/src/components/main-page/main-page.tsx
index b45bf2e..9366ff6 100644
--- a/src/components/main-page/main-page.tsx
+++ b/src/components/main-page/main-page.tsx
@@ -1,12 +1,15 @@
 import Logo from '../logo/logo';
 import { Link } from 'react-router-dom';
-import Card from '../card/card';
+import Cards from '../cards-list/cards-list';
+import { OffersPreview } from '../../types/offers-preview';
+import { addPluralEnding } from '../../utils/common';
+import { AppRoute } from '../../const/const';
 
 type MainPageProps = {
-  cardsCount: number;
+  offers: OffersPreview;
 };
 
-const MainPage = ({cardsCount}: MainPageProps): JSX.Element => (
+const MainPage = ({offers}: MainPageProps): JSX.Element => (
 
   <div className="page page--gray page--main">
     <header className="header">
@@ -16,7 +19,7 @@ const MainPage = ({cardsCount}: MainPageProps): JSX.Element => (
           <nav className="header__nav">
             <ul className="header__nav-list">
               <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
+                <Link className="header__nav-link header__nav-link--profile" to={`${AppRoute.Favorites}`}>
                   <div className="header__avatar-wrapper user__avatar-wrapper">
                   </div>
                   <span className="header__user-name user__name">Oliver.conner@gmail.com</span>
@@ -76,7 +79,7 @@ const MainPage = ({cardsCount}: MainPageProps): JSX.Element => (
         <div className="cities__places-container container">
           <section className="cities__places places">
             <h2 className="visually-hidden">Places</h2>
-            <b className="places__found">{cardsCount} places to stay in Amsterdam</b>
+            <b className="places__found">{offers.length} place{addPluralEnding(offers.length)} to stay in Amsterdam</b>
             <form className="places__sorting" action="#" method="get">
               <span className="places__sorting-caption">Sort by</span>
               <span className="places__sorting-type" tabIndex={0}>
@@ -93,13 +96,7 @@ const MainPage = ({cardsCount}: MainPageProps): JSX.Element => (
               </ul>
             </form>
             <div className="cities__places-list places__list tabs__content">
-
-              <Card/>
-              <Card/>
-              <Card/>
-              <Card/>
-              <Card/>
-
+              <Cards offers = {offers}/>
             </div>
           </section>
           <div className="cities__right-section">
diff --git a/src/components/offer-page/offer-page.tsx b/src/components/offer-page/offer-page.tsx
index dc0b2ff..71d1f0d 100644
--- a/src/components/offer-page/offer-page.tsx
+++ b/src/components/offer-page/offer-page.tsx
@@ -1,7 +1,11 @@
-import { Link } from 'react-router-dom';
+import { Link} from 'react-router-dom';
 import Logo from '../logo/logo';
+import { AppRoute } from '../../const/const';
+import ReviewForm from '../review-form/review-form';
+
 
 const OfferPage = (): JSX.Element => (
+
   <div className="page">
     <header className="header">
       <div className="container">
@@ -10,7 +14,7 @@ const OfferPage = (): JSX.Element => (
           <nav className="header__nav">
             <ul className="header__nav-list">
               <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
+                <Link className="header__nav-link header__nav-link--profile" to={`${AppRoute.Favorites}`}>
                   <div className="header__avatar-wrapper user__avatar-wrapper">
                   </div>
                   <span className="header__user-name user__name">Oliver.conner@gmail.com</span>
@@ -18,7 +22,7 @@ const OfferPage = (): JSX.Element => (
                 </Link>
               </li>
               <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
+                <Link className="header__nav-link" to={`${AppRoute.Login}`}>
                   <span className="header__signout">Sign out</span>
                 </Link>
               </li>
@@ -173,52 +177,7 @@ const OfferPage = (): JSX.Element => (
                   </div>
                 </li>
               </ul>
-              <form className="reviews__form form" action="#" method="post">
-                <label className="reviews__label form__label" htmlFor="review">Your review</label>
-                <div className="reviews__rating-form form__rating">
-                  <input className="form__rating-input visually-hidden" name="rating" value="5" id="5-stars" type="radio"></input>
-                  <label htmlFor="5-stars" className="reviews__rating-label form__rating-label" title="perfect">
-                    <svg className="form__star-image" width="37" height="33">
-                      <use xlinkHref="#icon-star"></use>
-                    </svg>
-                  </label>
-
-                  <input className="form__rating-input visually-hidden" name="rating" value="4" id="4-stars" type="radio"></input>
-                  <label htmlFor="4-stars" className="reviews__rating-label form__rating-label" title="good">
-                    <svg className="form__star-image" width="37" height="33">
-                      <use xlinkHref="#icon-star"></use>
-                    </svg>
-                  </label>
-
-                  <input className="form__rating-input visually-hidden" name="rating" value="3" id="3-stars" type="radio"></input>
-                  <label htmlFor="3-stars" className="reviews__rating-label form__rating-label" title="not bad">
-                    <svg className="form__star-image" width="37" height="33">
-                      <use xlinkHref="#icon-star"></use>
-                    </svg>
-                  </label>
-
-                  <input className="form__rating-input visually-hidden" name="rating" value="2" id="2-stars" type="radio"></input>
-                  <label htmlFor="2-stars" className="reviews__rating-label form__rating-label" title="badly">
-                    <svg className="form__star-image" width="37" height="33">
-                      <use xlinkHref="#icon-star"></use>
-                    </svg>
-                  </label>
-
-                  <input className="form__rating-input visually-hidden" name="rating" value="1" id="1-star" type="radio"></input>
-                  <label htmlFor="1-star" className="reviews__rating-label form__rating-label" title="terribly">
-                    <svg className="form__star-image" width="37" height="33">
-                      <use xlinkHref="#icon-star"></use>
-                    </svg>
-                  </label>
-                </div>
-                <textarea className="reviews__textarea form__textarea" id="review" name="review" placeholder="Tell how was your stay, what you like and what can be improved"></textarea>
-                <div className="reviews__button-wrapper">
-                  <p className="reviews__help">
-                      To submit review please make sure to set <span className="reviews__star">rating</span> and describe your stay with at least <b className="reviews__text-amount">50 characters</b>.
-                  </p>
-                  <button className="reviews__submit form__submit button" type="submit" disabled>Submit</button>
-                </div>
-              </form>
+              <ReviewForm/>
             </section>
           </div>
         </div>
@@ -230,7 +189,7 @@ const OfferPage = (): JSX.Element => (
           <div className="near-places__list places__list">
             <article className="near-places__card place-card">
               <div className="near-places__image-wrapper place-card__image-wrapper">
-                <Link to="#">
+                <Link to={`${AppRoute.Offer}`}>
                   <img className="place-card__image" src="img/room.jpg" width="260" height="200" alt="Place image"></img>
                 </Link>
               </div>
@@ -254,7 +213,7 @@ const OfferPage = (): JSX.Element => (
                   </div>
                 </div>
                 <h2 className="place-card__name">
-                  <Link to="#">Wood and stone place</Link>
+                  <Link to={`${AppRoute.Offer}`}>Wood and stone place</Link>
                 </h2>
                 <p className="place-card__type">Room</p>
               </div>
@@ -262,7 +221,7 @@ const OfferPage = (): JSX.Element => (
 
             <article className="near-places__card place-card">
               <div className="near-places__image-wrapper place-card__image-wrapper">
-                <Link to="#">
+                <Link to={`${AppRoute.Offer}`}>
                   <img className="place-card__image" src="img/apartment-02.jpg" width="260" height="200" alt="Place image"></img>
                 </Link>
               </div>
diff --git a/src/components/review-form/review-form.tsx b/src/components/review-form/review-form.tsx
new file mode 100644
index 0000000..7c7537a
--- /dev/null
+++ b/src/components/review-form/review-form.tsx
@@ -0,0 +1,72 @@
+import { Fragment, useState, ChangeEvent, useMemo } from 'react';
+import { ratingMap } from '../../const/const';
+
+const ReviewForm = () => {
+
+  const [form, setForm] = useState({
+    review: '',
+    rating: '',
+  });
+
+  const isValid = useMemo(() =>form.review.length >= 50 && form.rating !== '',[form.review, form.rating]);
+
+
+  function handleChange(evt: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) {
+    const {name, value} = evt.target;
+    setForm((prev) => ({
+      ...prev,
+      [name]: value,
+    }));
+  }
+
+  return (
+    <form className="reviews__form form" action="#" method="post">
+      <label className="reviews__label form__label" htmlFor="review">Your review</label>
+      <div className="reviews__rating-form form__rating">
+        {Object.entries(ratingMap)
+          .reverse()
+          .map(([score, title]) => (
+            <Fragment key={score}>
+              <input className="form__rating-input visually-hidden"
+                name="rating"
+                value={score}
+                id={`${score}-stars`} type="radio"
+                checked={form.rating === score}
+                onChange={handleChange}
+              />
+              <label htmlFor={`${score}-stars`} className="reviews__rating-label form__rating-label" title={title}>
+                <svg className="form__star-image" width="37" height="33">
+                  <use xlinkHref="#icon-star"></use>
+                </svg>
+              </label>
+            </Fragment>
+          ))}
+
+      </div>
+      <textarea
+        className="reviews__textarea form__textarea"
+        id="review"
+        name="review"
+        placeholder="Tell how was your stay, what you like and what can be improved"
+        value={form.review}
+        onChange={handleChange}
+      />
+      <div className="reviews__button-wrapper">
+        <p className="reviews__help">
+            To submit review please make sure to set
+          <span className="reviews__star">rating</span> and describe your stay with at least
+          <b className="reviews__text-amount">50 characters</b>.
+        </p>
+        <button
+          className="reviews__submit form__submit button"
+          type="submit"
+          disabled={!isValid}
+        >
+          Submit
+        </button>
+      </div>
+    </form>
+  );
+};
+
+export default ReviewForm;
diff --git a/src/const/const.tsx b/src/const/const.tsx
index 1356099..ded6ba1 100644
--- a/src/const/const.tsx
+++ b/src/const/const.tsx
@@ -7,7 +7,7 @@ export enum AppRoute {
   Main = '/',
   Login = '/login',
   Favorites = '/favorites',
-  Offer = '/offer/:id'
+  Offer = '/offer'
 }
 
 export enum AuthorizationStatus {
@@ -15,4 +15,22 @@ export enum AuthorizationStatus {
   NoAuth = 'NO_AUTH',
   Unknown = 'UNKNOWN',
 }
-export {Setting};
+
+export enum CityName {
+  Paris ='Paris',
+  Cologne = 'Cologne',
+  Brussels = 'Brussels',
+  Amsterdam = 'Amsterdam',
+  Hamburg = 'Hamburg',
+  Dusseldorf = 'Dusseldorf'
+}
+
+const ratingMap = {
+  '5' : 'perfect',
+  '4' : 'good',
+  '3' : 'not bad',
+  '2' : 'badly',
+  '1' : 'terribly',
+};
+
+export {Setting, ratingMap};
diff --git a/src/index.tsx b/src/index.tsx
index 1fa6e5e..43e6df8 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,7 +1,8 @@
 import React from 'react';
 import ReactDOM from 'react-dom/client';
 import App from './components/app/app';
-import { AuthorizationStatus, Setting } from './const/const';
+import { AuthorizationStatus } from './const/const';
+import { offersPreview } from './mock/offers-preview';
 
 
 const root = ReactDOM.createRoot(
@@ -11,8 +12,8 @@ const root = ReactDOM.createRoot(
 root.render(
   <React.StrictMode>
     <App
-      cardsCount={Setting.CardsCount}
-      authStatus={AuthorizationStatus.NoAuth}
+      authStatus={AuthorizationStatus.Auth}
+      offers={offersPreview}
     />
   </React.StrictMode>
 );
diff --git a/src/mock/offers-preview.ts b/src/mock/offers-preview.ts
new file mode 100644
index 0000000..6a2e357
--- /dev/null
+++ b/src/mock/offers-preview.ts
@@ -0,0 +1,97 @@
+import { OfferPreview } from '../types/offers-preview';
+import { CityName } from '../const/const';
+
+export const offersPreview: OfferPreview[] = [
+  {
+    id: '6af6f711-c28d-4121-82cd-e0b462a27f00',
+    title: 'Beautiful & luxurious studio at great location',
+    type: 'apartment',
+    price: 120,
+    city: {
+      name: CityName.Amsterdam,
+      location: {
+        latitude: 52.35514938496378,
+        longtitude: 4.673877537499948,
+        zoom: 8
+      }
+    },
+    location: {
+      latitude: 52.35514938496378,
+      longtitude: 4.673877537499948,
+      zoom: 8
+    },
+    isFavorite: true,
+    isPremium: true,
+    rating: 2,
+    previewImage: '../markup/img/apartment-01.jpg'
+  },
+  {
+    id: '9af6f221-h28f-3521-82cd-e0b882a27f00',
+    title: 'Beautiful & luxurious house at quiet area',
+    type: 'Detached house',
+    price: 200,
+    city: {
+      name: CityName.Hamburg,
+      location: {
+        latitude: 32.35511118467378,
+        longtitude: 15.67387123499948,
+        zoom: 5
+      }
+    },
+    location: {
+      latitude: 32.35511118467378,
+      longtitude: 15.67387123499948,
+      zoom: 5
+    },
+    isFavorite: false,
+    isPremium: true,
+    rating: 5,
+    previewImage: '../markup/img/apartment-03.jpg'
+  },
+  {
+    id: '4gf2f449-h99k-1121-82lm-e0b882a55f00',
+    title: 'Luxurious flat in the city center',
+    type: 'Flat',
+    price: 100,
+    city: {
+      name: CityName.Brussels,
+      location: {
+        latitude: 12.35511118467378,
+        longtitude: 65.67387123499948,
+        zoom: 4
+      }
+    },
+    location: {
+      latitude: 12.35511118467378,
+      longtitude: 65.67387123499948,
+      zoom: 4
+    },
+    isFavorite: false,
+    isPremium: false,
+    rating: 3,
+    previewImage: '../markup/img/apartment-02.jpg'
+  },
+  {
+    id: '7ff2d234-s99s-2222-97lg-e0b882a55f00',
+    title: 'Modern and comfortable mansion',
+    type: 'Mansion',
+    price: 400,
+    city: {
+      name: CityName.Paris,
+      location: {
+        latitude: 22.35523518411178,
+        longtitude: 45.67387123499948,
+        zoom: 8
+      }
+    },
+    location: {
+      latitude: 22.35523518411178,
+      longtitude: 45.67387123499948,
+      zoom: 8
+    },
+    isFavorite: true,
+    isPremium: false,
+    rating: 5,
+    previewImage: '../markup/img/apartment-03.jpg'
+  },
+];
diff --git a/src/mock/reviews.ts b/src/mock/reviews.ts
new file mode 100644
index 0000000..08aac50
--- /dev/null
+++ b/src/mock/reviews.ts
@@ -0,0 +1,50 @@
+import { Review } from '../types/reviews';
+
+const AVATAR_URL = 'https://i.pravatar.cc/128';
+
+export const Reviews: Review[] = [
+  {
+    id: 'b67ddfd5-b953-4a30-8c8d-bd083cd6b62a',
+    date: '2019-05-08T14:13:56.569Z',
+    user: {
+      name: 'Oliver Conner',
+      avatarUrl: `${AVATAR_URL}?rnd=${Math.random()}`,
+      isPro: false
+    },
+    comment: 'A quiet cozy and picturesque that hides behind a a river by the unique lightness of Amsterdam.',
+    rating: 4
+  },
+  {
+    id: 'b65ddfd7-b943-4a90-9c9d-bd099cd6b62a',
+    date: '2023-07-08T14:16:56.569Z',
+    user: {
+      name: 'Lolla Connor',
+      avatarUrl: `${AVATAR_URL}?rnd=${Math.random()}`,
+      isPro: false
+    },
+    comment: 'I really love this place!',
+    rating: 5
+  },
+  {
+    id: 'c65ddgd6-b555-4a90-9c9d-bd099cd6b62a',
+    date: '2021-05-08T17:16:56.469Z',
+    user: {
+      name: 'Lolik Black',
+      avatarUrl: `${AVATAR_URL}?rnd=${Math.random()}`,
+      isPro: true
+    },
+    comment: 'Norm.',
+    rating: 3
+  },
+  {
+    id: 'b25fffs2-b941-2a90-9s9b-bd099cd6b62a',
+    date: '2021-05-08T17:16:56.469Z',
+    user: {
+      name: 'Jacob Cullen',
+      avatarUrl: `${AVATAR_URL}?rnd=${Math.random()}`,
+      isPro: false
+    },
+    comment: 'I will defenetly come back here charmingly!',
+    rating: 5
+  },
+];
diff --git a/src/types/offers-preview.ts b/src/types/offers-preview.ts
new file mode 100644
index 0000000..e27108e
--- /dev/null
+++ b/src/types/offers-preview.ts
@@ -0,0 +1,25 @@
+export type Location = {
+  latitude: number;
+  longtitude:number;
+  zoom:number;
+}
+
+export type City = {
+  name:string;
+  location:Location;
+}
+
+export type OfferPreview = {
+  id: string;
+  title: string;
+  type: string;
+  price: number;
+  city: City;
+  location: Location;
+  isFavorite: boolean;
+  isPremium : boolean;
+  rating: number;
+  previewImage: string;
+}
+
+export type OffersPreview = OfferPreview[];
diff --git a/src/types/reviews.ts b/src/types/reviews.ts
new file mode 100644
index 0000000..dde0dd7
--- /dev/null
+++ b/src/types/reviews.ts
@@ -0,0 +1,15 @@
+export type User = {
+  name: string;
+  avatarUrl:string;
+  isPro:boolean;
+}
+
+export type Review = {
+  id: string;
+  date: string;
+  user: User;
+  comment: string;
+  rating: number;
+}
+
+export type Reviews = Review[];
diff --git a/src/utils/cards.ts b/src/utils/cards.ts
new file mode 100644
index 0000000..50a10b4
--- /dev/null
+++ b/src/utils/cards.ts
@@ -0,0 +1,5 @@
+function getRatingWidth(count:number) {
+  return count * 20;
+}
+
+export {getRatingWidth};
diff --git a/src/utils/common.ts b/src/utils/common.ts
new file mode 100644
index 0000000..f822f5e
--- /dev/null
+++ b/src/utils/common.ts
@@ -0,0 +1,10 @@
+import { AppRoute } from '../const/const';
+
+function addPluralEnding (count:number) {
+  return count !== 1 ? 's' : '';
+}
+
+const getOfferPath = (offerId: string) =>
+  `${AppRoute.Offer}/${offerId}`;
+
+export {addPluralEnding, getOfferPath};
diff --git a/src/utils/favorities-by-city.ts b/src/utils/favorities-by-city.ts
new file mode 100644
index 0000000..68505cf
--- /dev/null
+++ b/src/utils/favorities-by-city.ts
@@ -0,0 +1,15 @@
+import { OfferPreview } from '../types/offers-preview';
+
+const getFavoritiesByCity = (favorites: OfferPreview[]) =>
+  favorites.reduce<{ [key: string]: OfferPreview[]}>((acc,curr) => {
+    const city = curr.city.name;
+
+    if(!(city in acc)) {
+      acc[city] = [];
+    }
+    acc[city].push(curr);
+
+    return acc;
+  }, {});
+
+export default getFavoritiesByCity;


Reviews:
user: login: BotaniQQQuser
state: CHANGES_REQUESTED
author_association: NONE
submitted_at: 2025-03-24T11:05:54Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T13:30:07Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T14:30:28Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T14:31:31Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T14:37:12Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T14:59:26Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T16:02:47Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T16:17:19Z
user: login: BotaniQQQuser
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-24T16:27:19Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-24T16:59:03Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-25T02:32:36Z
user: login: BotaniQQQuser
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-25T14:57:29Z
user: login: Suninall
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-26T03:19:11Z

Review comments:
diff_hunk: @@ -0,0 +1,5 @@
+function getRaitingWidth(count:number) {
path: src/utils/cards.ts
user: login: BotaniQQQuser
body: Очепятка в `Rating`
created_at: 2025-03-24T05:13:42Z
author_association: NONE
diff_hunk: @@ -0,0 +1,19 @@
+import {OfferPreview } from './offers-preview';
+
+
+export type Host = {
+  name: string;
+  avatarUrl: string;
+  isPro: boolean;
+}
+export type Offer = OfferPreview & {
path: src/types/offers.ts
user: login: BotaniQQQuser
body: В обоих методах, которые возвращают список предложений, нет этих полей:)  
В моках, соответственно, тоже стоит убрать и работать с типом `OfferPreview`. Можешь его переименовать в `Offer`, чтобы меньше исправлять
created_at: 2025-03-24T05:27:57Z
author_association: NONE
diff_hunk: @@ -0,0 +1,68 @@
+import { Fragment, useState, ChangeEvent } from 'react';
+import { ratingMap } from '../../const/const';
+
+const ReviewForm = () => {
+
+  const [comment,setComment] = useState('');
path: src/components/review-form/review-form.tsx
user: login: BotaniQQQuser
body: Можно собрать оба поля в объект и использовать один `useState`  для редактирования (метод апи добавления нового комментария принимает как раз объект)
created_at: 2025-03-24T05:34:50Z
author_association: NONE
diff_hunk: @@ -0,0 +1,68 @@
+import { Fragment, useState, ChangeEvent } from 'react';
+import { ratingMap } from '../../const/const';
+
+const ReviewForm = () => {
+
+  const [comment,setComment] = useState('');
+  const [rating, setRaiting] = useState('');
+  const isValid = rating !== '';
path: src/components/review-form/review-form.tsx
user: login: BotaniQQQuser
body: Значение `isValid` будет пересчитываться при каждом ререндере компонента (даже если рейтинг не менялся)  
Чтобы этого избежать, можно использовать [useMemo](https://react.dev/reference/react/useMemo)
created_at: 2025-03-24T05:38:03Z
author_association: NONE
diff_hunk: @@ -38,8 +40,8 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
-        element ={<OfferPage/>}
+        path={`${AppRoute.Offer}/:offerId`}
path: src/components/app/app.tsx
user: login: BotaniQQQuser
body: Ссылка на конкретное предложение формируется в нескольких местах  
Избавимся от дублирования?
created_at: 2025-03-24T05:44:27Z
author_association: NONE
diff_hunk: @@ -1,39 +1,60 @@
 import { Link } from 'react-router-dom';
+import { OfferPreview } from '../../types/offers-preview';
+import { AppRoute } from '../../const/const';
+import { getRaitingWidth } from '../../utils/cards';
+import { useState} from 'react';
 
-const Card = (): JSX.Element => (
-  <article className="cities__card place-card">
-    <div className="place-card__mark">
-      <span>Premium</span>
-    </div>
-    <div className="cities__image-wrapper place-card__image-wrapper">
-      <Link to="#">
-        <img className="place-card__image" src="img/apartment-01.jpg" width="260" height="200" alt="Place image"></img>
-      </Link>
-    </div>
-    <div className="place-card__info">
-      <div className="place-card__price-wrapper">
-        <div className="place-card__price">
-          <b className="place-card__price-value">&euro;120</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>
+type CardProps = {
+  offer: OfferPreview;
+  block: string;
+}
+
+const Card = ({offer, block}: CardProps): JSX.Element => {
+
+  const {isPremium, previewImage, id, price, rating, title, type } = offer;
+
+  const [, setActiveCard] = useState<string| null>(null);
path: src/components/card/card.tsx
user: login: BotaniQQQuser
body: Сейчас получается, что каждая карточка сама знает о том, что она активная
created_at: 2025-03-24T05:46:22Z
author_association: NONE
diff_hunk: @@ -0,0 +1,57 @@
+import { OfferPreview } from '../../types/offers-preview';
+import { Link } from 'react-router-dom';
+import { getRaitingWidth } from '../../utils/cards';
+import { AppRoute } from '../../const/const';
+
+type FavoritiesCardProps = {
+  offer: OfferPreview;
+}
+
+const FavoritiesCard = ({offer}: FavoritiesCardProps): JSX.Element | null => {
path: src/components/favorites-card/favorities-card.tsx
user: login: BotaniQQQuser
body: У нас тут появился компонент для избранного предложения, но что-то мне подсказывает, что разметка его практически не отличается от разметки карточки обычного предложения
created_at: 2025-03-24T06:56:15Z
author_association: NONE
diff_hunk: @@ -1,167 +1,86 @@
 import { Link } from 'react-router-dom';
 import Logo from '../logo/logo';
+import { OfferPreview } from '../../types/offers-preview';
+import FavoritiesCard from '../favorites-card/favorities-card';
 
-const FavoritesPage = (): JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <Logo/>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
-                  <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>
-                </Link>
-              </li>
-              <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
-                  <span className="header__signout">Sign out</span>
-                </Link>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
+type FavoritiesProps = {
+  offers: OfferPreview[];
+}
 
-    <main className="page__main page__main--favorites">
-      <div className="page__favorites-container container">
-        <section className="favorites">
-          <h1 className="favorites__title">Saved listing</h1>
-          <ul className="favorites__list">
-            <li className="favorites__locations-items">
-              <div className="favorites__locations locations locations--current">
-                <div className="locations__item">
-                  <Link className="locations__item-link" to="#">
-                    <span>Amsterdam</span>
-                  </Link>
-                </div>
-              </div>
-              <div className="favorites__places">
-                <article className="favorites__card place-card">
-                  <div className="place-card__mark">
-                    <span>Premium</span>
-                  </div>
-                  <div className="favorites__image-wrapper place-card__image-wrapper">
-                    <Link to="#">
-                      <img className="place-card__image" src="img/apartment-small-03.jpg" width="150" height="110" alt="Place image"></img>
-                    </Link>
-                  </div>
-                  <div className="favorites__card-info 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 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: '100%'}}></span>
-                        <span className="visually-hidden">Rating</span>
-                      </div>
-                    </div>
-                    <h2 className="place-card__name">
-                      <Link to="#">Nice, cozy, warm big bed apartment</Link>
-                    </h2>
-                    <p className="place-card__type">Apartment</p>
-                  </div>
-                </article>
+const getFavoritiesByCity = (favorites: OfferPreview[]) =>
path: src/components/favorites-page/favorites-page.tsx
user: login: BotaniQQQuser
body: Здорово, что вынесла группировку предложений по городам в отдельную функцию  
Давай еще её унесем в отдельный файл? Так будет проще её переиспользовать при необходимости
created_at: 2025-03-24T06:58:11Z
author_association: NONE
diff_hunk: @@ -1,336 +1,162 @@
-import { Link } from 'react-router-dom';
+import { Link, useParams, Navigate } from 'react-router-dom';
 import Logo from '../logo/logo';
+import { Offer } from '../../types/offers';
+import { AppRoute } from '../../const/const';
+import OfferInformation from '../offerInformation/offerInformation';
 
-const OfferPage = (): JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <Logo/>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
-                  <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>
-                </Link>
-              </li>
-              <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
-                  <span className="header__signout">Sign out</span>
-                </Link>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
+type OfferPageProps = {
+  offers: Offer[];
+}
 
-    <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"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-02.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-03.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/studio-01.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio"></img>
-            </div>
-          </div>
-        </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>
-              </div>
-              <span className="offer__rating-value rating__value">4.8</span>
-            </div>
-            <ul className="offer__features">
-              <li className="offer__feature offer__feature--entire">
-                  Apartment
-              </li>
-              <li className="offer__feature offer__feature--bedrooms">
-                  3 Bedrooms
-              </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">
-                    Washing machine
-                </li>
-                <li className="offer__inside-item">
-                    Towels
-                </li>
-                <li className="offer__inside-item">
-                    Heating
-                </li>
-                <li className="offer__inside-item">
-                    Coffee machine
-                </li>
-                <li className="offer__inside-item">
-                    Baby seat
-                </li>
-                <li className="offer__inside-item">
-                    Kitchen
-                </li>
-                <li className="offer__inside-item">
-                    Dishwasher
-                </li>
-                <li className="offer__inside-item">
-                    Cabel TV
+const OfferPage = ({offers}: OfferPageProps): JSX.Element => {
path: src/components/offer-page/offer-page.tsx
user: login: BotaniQQQuser
body: В этом компоненте нам нужно было только формочку пока что поменять  
Может вернем исходную верстку пока что? Так и компонент `OfferInformation` будет не нужен
created_at: 2025-03-24T11:05:25Z
author_association: NONE
diff_hunk: @@ -0,0 +1,5 @@
+function getRaitingWidth(count:number) {
path: src/utils/cards.ts
user: login: Suninall
body: Исправила
created_at: 2025-03-24T13:30:06Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,68 @@
+import { Fragment, useState, ChangeEvent } from 'react';
+import { ratingMap } from '../../const/const';
+
+const ReviewForm = () => {
+
+  const [comment,setComment] = useState('');
path: src/components/review-form/review-form.tsx
user: login: Suninall
body: Исправила 
created_at: 2025-03-24T14:30:28Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,68 @@
+import { Fragment, useState, ChangeEvent } from 'react';
+import { ratingMap } from '../../const/const';
+
+const ReviewForm = () => {
+
+  const [comment,setComment] = useState('');
+  const [rating, setRaiting] = useState('');
+  const isValid = rating !== '';
path: src/components/review-form/review-form.tsx
user: login: Suninall
body: Добавила
created_at: 2025-03-24T14:31:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,167 +1,86 @@
 import { Link } from 'react-router-dom';
 import Logo from '../logo/logo';
+import { OfferPreview } from '../../types/offers-preview';
+import FavoritiesCard from '../favorites-card/favorities-card';
 
-const FavoritesPage = (): JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <Logo/>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
-                  <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>
-                </Link>
-              </li>
-              <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
-                  <span className="header__signout">Sign out</span>
-                </Link>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
+type FavoritiesProps = {
+  offers: OfferPreview[];
+}
 
-    <main className="page__main page__main--favorites">
-      <div className="page__favorites-container container">
-        <section className="favorites">
-          <h1 className="favorites__title">Saved listing</h1>
-          <ul className="favorites__list">
-            <li className="favorites__locations-items">
-              <div className="favorites__locations locations locations--current">
-                <div className="locations__item">
-                  <Link className="locations__item-link" to="#">
-                    <span>Amsterdam</span>
-                  </Link>
-                </div>
-              </div>
-              <div className="favorites__places">
-                <article className="favorites__card place-card">
-                  <div className="place-card__mark">
-                    <span>Premium</span>
-                  </div>
-                  <div className="favorites__image-wrapper place-card__image-wrapper">
-                    <Link to="#">
-                      <img className="place-card__image" src="img/apartment-small-03.jpg" width="150" height="110" alt="Place image"></img>
-                    </Link>
-                  </div>
-                  <div className="favorites__card-info 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 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: '100%'}}></span>
-                        <span className="visually-hidden">Rating</span>
-                      </div>
-                    </div>
-                    <h2 className="place-card__name">
-                      <Link to="#">Nice, cozy, warm big bed apartment</Link>
-                    </h2>
-                    <p className="place-card__type">Apartment</p>
-                  </div>
-                </article>
+const getFavoritiesByCity = (favorites: OfferPreview[]) =>
path: src/components/favorites-page/favorites-page.tsx
user: login: Suninall
body: Вынесла
created_at: 2025-03-24T14:37:12Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,57 @@
+import { OfferPreview } from '../../types/offers-preview';
+import { Link } from 'react-router-dom';
+import { getRaitingWidth } from '../../utils/cards';
+import { AppRoute } from '../../const/const';
+
+type FavoritiesCardProps = {
+  offer: OfferPreview;
+}
+
+const FavoritiesCard = ({offer}: FavoritiesCardProps): JSX.Element | null => {
path: src/components/favorites-card/favorities-card.tsx
user: login: Suninall
body: Заменила на отрисовку обычной карточки
created_at: 2025-03-24T14:59:25Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,336 +1,162 @@
-import { Link } from 'react-router-dom';
+import { Link, useParams, Navigate } from 'react-router-dom';
 import Logo from '../logo/logo';
+import { Offer } from '../../types/offers';
+import { AppRoute } from '../../const/const';
+import OfferInformation from '../offerInformation/offerInformation';
 
-const OfferPage = (): JSX.Element => (
-  <div className="page">
-    <header className="header">
-      <div className="container">
-        <div className="header__wrapper">
-          <Logo/>
-          <nav className="header__nav">
-            <ul className="header__nav-list">
-              <li className="header__nav-item user">
-                <Link className="header__nav-link header__nav-link--profile" to="#">
-                  <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>
-                </Link>
-              </li>
-              <li className="header__nav-item">
-                <Link className="header__nav-link" to="/login">
-                  <span className="header__signout">Sign out</span>
-                </Link>
-              </li>
-            </ul>
-          </nav>
-        </div>
-      </div>
-    </header>
+type OfferPageProps = {
+  offers: Offer[];
+}
 
-    <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"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-02.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-03.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/studio-01.jpg" alt="Photo studio"></img>
-            </div>
-            <div className="offer__image-wrapper">
-              <img className="offer__image" src="img/apartment-01.jpg" alt="Photo studio"></img>
-            </div>
-          </div>
-        </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>
-              </div>
-              <span className="offer__rating-value rating__value">4.8</span>
-            </div>
-            <ul className="offer__features">
-              <li className="offer__feature offer__feature--entire">
-                  Apartment
-              </li>
-              <li className="offer__feature offer__feature--bedrooms">
-                  3 Bedrooms
-              </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">
-                    Washing machine
-                </li>
-                <li className="offer__inside-item">
-                    Towels
-                </li>
-                <li className="offer__inside-item">
-                    Heating
-                </li>
-                <li className="offer__inside-item">
-                    Coffee machine
-                </li>
-                <li className="offer__inside-item">
-                    Baby seat
-                </li>
-                <li className="offer__inside-item">
-                    Kitchen
-                </li>
-                <li className="offer__inside-item">
-                    Dishwasher
-                </li>
-                <li className="offer__inside-item">
-                    Cabel TV
+const OfferPage = ({offers}: OfferPageProps): JSX.Element => {
path: src/components/offer-page/offer-page.tsx
user: login: Suninall
body: Исправила
created_at: 2025-03-24T16:02:47Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,19 @@
+import {OfferPreview } from './offers-preview';
+
+
+export type Host = {
+  name: string;
+  avatarUrl: string;
+  isPro: boolean;
+}
+export type Offer = OfferPreview & {
path: src/types/offers.ts
user: login: Suninall
body: Оставила только один тип 
created_at: 2025-03-24T16:17:18Z
author_association: CONTRIBUTOR
diff_hunk: @@ -38,8 +40,8 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
-        element ={<OfferPage/>}
+        path={`${AppRoute.Offer}/:offerId`}
path: src/components/app/app.tsx
user: login: BotaniQQQuser
body: Пардон, я не туда комментарий прилепил🤦‍♂️ 
Я про ссылку ``${AppRoute.Offer}/${id}`` имел ввиду
created_at: 2025-03-24T16:27:19Z
author_association: NONE
diff_hunk: @@ -38,8 +40,8 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
-        element ={<OfferPage/>}
+        path={`${AppRoute.Offer}/:offerId`}
path: src/components/app/app.tsx
user: login: Suninall
body: Убрала дублирование
created_at: 2025-03-24T16:59:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -1,39 +1,60 @@
 import { Link } from 'react-router-dom';
+import { OfferPreview } from '../../types/offers-preview';
+import { AppRoute } from '../../const/const';
+import { getRaitingWidth } from '../../utils/cards';
+import { useState} from 'react';
 
-const Card = (): JSX.Element => (
-  <article className="cities__card place-card">
-    <div className="place-card__mark">
-      <span>Premium</span>
-    </div>
-    <div className="cities__image-wrapper place-card__image-wrapper">
-      <Link to="#">
-        <img className="place-card__image" src="img/apartment-01.jpg" width="260" height="200" alt="Place image"></img>
-      </Link>
-    </div>
-    <div className="place-card__info">
-      <div className="place-card__price-wrapper">
-        <div className="place-card__price">
-          <b className="place-card__price-value">&euro;120</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>
+type CardProps = {
+  offer: OfferPreview;
+  block: string;
+}
+
+const Card = ({offer, block}: CardProps): JSX.Element => {
+
+  const {isPremium, previewImage, id, price, rating, title, type } = offer;
+
+  const [, setActiveCard] = useState<string| null>(null);
path: src/components/card/card.tsx
user: login: Suninall
body: Исправила 
created_at: 2025-03-25T02:32:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -38,8 +40,8 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
-        element ={<OfferPage/>}
+        path={`${AppRoute.Offer}/:offerId`}
path: src/components/app/app.tsx
user: login: BotaniQQQuser
body: А где именно убрала?)  
В компоненте карточки предложения ссылка на предложение как на картинке, так и на заголовке формируется с помощью строчки `${AppRoute.Offer}/${id}`
created_at: 2025-03-25T14:57:29Z
author_association: NONE
diff_hunk: @@ -38,8 +40,8 @@ const App = ({cardsCount, authStatus}: AppScreenProps): JSX.Element => (
         element ={<LoginComponent/>}
       />
       <Route
-        path={AppRoute.Offer}
-        element ={<OfferPage/>}
+        path={`${AppRoute.Offer}/:offerId`}
path: src/components/app/app.tsx
user: login: Suninall
body: Не так поняла сначала,  подумала, что ты про дублирование в маршруте, там раньше было offer/id/9af6f221-h28f-3521-82cd-e0b882a27f00
Подумала от этого дублирования нужно избавиться
Сейчас поправила, создала отдельную функцию, которая возвращает путь 
created_at: 2025-03-26T03:19:10Z
author_association: CONTRIBUTOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-03-22T10:00:57Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-22T10:52:09Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-23T16:34:28Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T14:30:58Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T14:59:53Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T16:08:46Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T16:17:57Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T16:35:00Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-24T16:59:23Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-03-26T03:20:42Z
body: Ваш пулреквест опубликован. Посмотреть можно [здесь](https://htmlacademy-univer-javascript-3.github.io/2579369-six-cities-5/4/)
author_association: NONE