diff --git a/src/components/app/app.tsx b/src/components/app/app.tsx index 19a8337..e9121fa 100644 --- a/src/components/app/app.tsx +++ b/src/components/app/app.tsx @@ -1,27 +1,30 @@ import MainScreen from '../../pages/main-screen/main-screen'; -import {BrowserRouter, Route, Routes} from 'react-router-dom'; +import { BrowserRouter, Route, Routes } from 'react-router-dom'; import LoginScreen from '../../pages/login-screen/login-screen.tsx'; import FavoritesScreen from '../../pages/favorites-screen/favorites-screen.tsx'; import NotFoundScreen from '../../pages/not-found-screen/not-found-screen.tsx'; import OfferScreen from '../../pages/offer-screen/offer-screen.tsx'; import PrivateRoute from '../private-route/private-route.tsx'; import { AppRoute, AuthorizationStatus } from '../../const.ts'; +import { Offer } from '../../types/offer'; type AppScreenProps = { placesCount: number; + offers: Offer[]; } -function App({placesCount}: AppScreenProps): JSX.Element { +function App({placesCount, offers}: AppScreenProps): JSX.Element { + const favourites: Offer[] = offers.filter((o) => o.isFavorite); return ( } /> - } /> + } /> - + } /> diff --git a/src/components/city-card/city-card.tsx b/src/components/city-card/city-card.tsx index c43e1ac..bbb136d 100644 --- a/src/components/city-card/city-card.tsx +++ b/src/components/city-card/city-card.tsx @@ -1,18 +1,30 @@ -function CityCard(): JSX.Element { +import { Offer } from '../../types/offer'; +import { Link } from 'react-router-dom'; + +type OfferProps = { + offer: Offer; +} + +function CityCard({offer}: OfferProps): JSX.Element { return (
+ {offer.isPremium ? ( +
+ Premium +
+ ) : null}
- €132 + €{offer.price} / night
-
- + Rating

- Canal View Prinsengracht + {offer.title}

-

Apartment

+

{offer.type}

); diff --git a/src/components/comment-form/comment-form.tsx b/src/components/comment-form/comment-form.tsx new file mode 100644 index 0000000..f1a98a5 --- /dev/null +++ b/src/components/comment-form/comment-form.tsx @@ -0,0 +1,65 @@ +import { useState } from 'react'; + +function CommentForm(): JSX.Element { + const [formData, setFormData] = useState({ + rating: '1', + review: '', + }); + const handleFieldChange = (evt: React.ChangeEvent): void => { + const {name, value} = evt.target; + setFormData({ + ...formData, + [name]: value + }); + }; + + return ( +
+ +
+ + + + + + + + + + + + + + +
+ +
+

+ To submit review please make sure to set rating and describe your stay with at least 50 characters. +

+ +
+
+ ); +} +export default CommentForm; diff --git a/src/components/offer-list/offer-list.tsx b/src/components/offer-list/offer-list.tsx new file mode 100644 index 0000000..96d1f73 --- /dev/null +++ b/src/components/offer-list/offer-list.tsx @@ -0,0 +1,17 @@ +import { Offer } from '../../types/offer'; +import CityCard from '../city-card/city-card'; + +type OfferListProps = { + offers: Offer[]; +}; + +function OfferList({offers}: OfferListProps): JSX.Element { + return ( +
+ {offers.map((offer) => ( + + ))} +
+ ); +} +export default OfferList; diff --git a/src/index.tsx b/src/index.tsx index 7b62b8d..83054b7 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 { Settings } from './const'; +import { offers } from './mocks/offers'; const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement @@ -9,6 +10,6 @@ const root = ReactDOM.createRoot( root.render( - + ); diff --git a/src/mocks/offers.ts b/src/mocks/offers.ts new file mode 100644 index 0000000..fd225fa --- /dev/null +++ b/src/mocks/offers.ts @@ -0,0 +1,49 @@ +import { Offer } from '../types/offer'; +import { reviews } from './reviews'; + +export const offers: Offer[] = [ + { + id: '1', + image: ['img/apartment-01.jpg'], + isPremium: true, + price: 120, + title: 'Beautiful & luxurious studio at great location', + type: 'Apartment', + isFavorite: false, + rating: 4, + reviews: [reviews[0]] + }, + { + id: '2', + image: ['img/room.jpg'], + isPremium: false, + price: 80, + title: 'Wood and stone place', + type: 'Room', + isFavorite: true, + rating: 4, + reviews: [reviews[1]] + }, + { + id: '3', + image: ['img/apartment-02.jpg'], + isPremium: false, + price: 132, + title: 'Canal View Prinsengracht', + type: 'Apartment', + isFavorite: false, + rating: 4, + reviews: [reviews[2]] + }, + { + id: '4', + image: ['img/apartment-03.jpg'], + isPremium: true, + price: 180, + title: 'Nice, cozy, warm big bed apartment', + type: 'Apartment', + isFavorite: true, + rating: 5, + reviews: [reviews[3]] + }, +]; diff --git a/src/mocks/reviews.ts b/src/mocks/reviews.ts new file mode 100644 index 0000000..b6d9edc --- /dev/null +++ b/src/mocks/reviews.ts @@ -0,0 +1,36 @@ +import { Review } from '../types/review'; + +export const reviews: Review[] = [ + { + id: '1', + avatar: 'img/avatar-angelina.jpg', + author: 'Angelina', + rating: 5, + date: 'March 2022', + comment: 'Beautiful apartments with stunning views, perfect for those who appreciate comfort and beauty.' + }, + { + id: '2', + avatar: 'img/avatar-max.jpg', + author: 'Max', + rating: 3, + date: 'December 2023', + comment: 'The room is cozy but lacks sufficient heating, making it uncomfortable during colder months.' + }, + { + id: '3', + avatar: 'img/avatar-angelina.jpg', + author: 'Angelina', + rating: 5, + date: 'May 2024', + comment: 'Well equipped apartment in a great location with all possible amenities.' + }, + { + id: '4', + avatar: 'img/avatar-max.jpg', + author: 'Max', + rating: 5, + date: 'December 2024', + comment: 'Luxurious apartments with breathtaking views, ideal for those seeking both comfort and elegance in a prime location.' + } +]; diff --git a/src/pages/favorites-screen/favorites-screen.tsx b/src/pages/favorites-screen/favorites-screen.tsx index 443a39c..a4db42d 100644 --- a/src/pages/favorites-screen/favorites-screen.tsx +++ b/src/pages/favorites-screen/favorites-screen.tsx @@ -1,13 +1,21 @@ -function FavoritesScreen(): JSX.Element { +import { Offer } from '../../types/offer'; +import Card from '../../components/city-card/city-card'; +import { Link } from 'react-router-dom'; + +type FavoritesScreenProps = { + offers: Offer[]; +}; + +function FavoritesScreen({offers}: FavoritesScreenProps): JSX.Element { return (
- + 6 cities logo - +
- - - -
- - -
  • - -
    -
    -
    - - Place image - -
    -
    -
    -
    - €180 - / night -
    - -
    -
    -
    - - Rating -
    -
    -

    - White castle -

    -

    Apartment

    -
    -
    + {offers.map((offer) => + + )}
  • @@ -160,9 +62,9 @@ function FavoritesScreen(): JSX.Element {
    ); diff --git a/src/pages/main-screen/main-screen.tsx b/src/pages/main-screen/main-screen.tsx index 9c9fa2f..ca5edb0 100644 --- a/src/pages/main-screen/main-screen.tsx +++ b/src/pages/main-screen/main-screen.tsx @@ -1,10 +1,13 @@ -import CityCard from '../../components/city-card/city-card'; +import { Offer } from '../../types/offer'; +import OfferList from '../../components/offer-list/offer-list'; +import { Link } from 'react-router-dom'; type MainScreenProps = { placesCount: number; + offers: Offer[]; } -function MainScreen({placesCount}: MainScreenProps): JSX.Element { +function MainScreen({placesCount, offers}: MainScreenProps): JSX.Element { return (
    @@ -22,7 +25,9 @@ function MainScreen({placesCount}: MainScreenProps): JSX.Element {
    Oliver.conner@gmail.com - 3 + + 3 +
  • @@ -94,13 +99,7 @@ function MainScreen({placesCount}: MainScreenProps): JSX.Element {
  • Top rated first
  • -
    - - - - - -
    +
    diff --git a/src/pages/offer-screen/offer-screen.tsx b/src/pages/offer-screen/offer-screen.tsx index bcaa301..6809959 100644 --- a/src/pages/offer-screen/offer-screen.tsx +++ b/src/pages/offer-screen/offer-screen.tsx @@ -1,3 +1,6 @@ +import { Link } from 'react-router-dom'; +import CommentForm from '../../components/comment-form/comment-form'; + function OfferScreen(): JSX.Element { return (
    @@ -5,9 +8,9 @@ function OfferScreen(): JSX.Element {
    - + 6 cities logo - +
    -
    - -
    - - - - - - - - - - - - - - -
    - -
    -

    - To submit review please make sure to set rating and describe your stay with at least 50 characters. -

    - -
    -
    +
    diff --git a/src/types/offer.ts b/src/types/offer.ts new file mode 100644 index 0000000..cbe3352 --- /dev/null +++ b/src/types/offer.ts @@ -0,0 +1,13 @@ +import { Review } from '../types/review'; + +export type Offer = { + id: string; + image: string[]; + isPremium: boolean; + price: number; + title: string; + type: string; + isFavorite: boolean; + rating: number; + reviews: Review[]; +}; diff --git a/src/types/review.ts b/src/types/review.ts new file mode 100644 index 0000000..9559c4c --- /dev/null +++ b/src/types/review.ts @@ -0,0 +1,8 @@ +export type Review = { + id: string; + avatar: string; + author: string; + rating: number; + date: string; + comment: string; +}