Skip to content

Commit

Permalink
module4-task1
Browse files Browse the repository at this point in the history
  • Loading branch information
Mayanzev committed Mar 17, 2024
1 parent df0f500 commit d0e223b
Show file tree
Hide file tree
Showing 12 changed files with 250 additions and 185 deletions.
11 changes: 7 additions & 4 deletions src/components/app/app.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<BrowserRouter>
<Routes>
<Route path="*" element={<NotFoundScreen/>} />
<Route path={AppRoute.Main} element={<MainScreen placesCount={placesCount}/>} />
<Route path={AppRoute.Main} element={<MainScreen placesCount={placesCount} offers={offers}/>} />
<Route
path={AppRoute.Favorites}
element={
<PrivateRoute authorizationStatus={AuthorizationStatus.NoAuth} >
<FavoritesScreen/>
<FavoritesScreen offers={favourites}/>
</PrivateRoute>
}
/>
Expand Down
26 changes: 19 additions & 7 deletions src/components/city-card/city-card.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<article className="cities__card place-card">
{offer.isPremium ? (
<div className="place-card__mark">
<span>Premium</span>
</div>
) : null}
<div className="cities__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"/>
<img className="place-card__image" src={offer.image[0]} 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>
<b className="place-card__price-value">&euro;{offer.price}</b>
<span className="place-card__price-text">&#47;&nbsp;night</span>
</div>
<button className="place-card__bookmark-button button" type="button">
<button className={offer.isFavorite ? 'place-card__bookmark-button place-card__bookmark-button--active button' : 'place-card__bookmark-button button'} type="button">
<svg className="place-card__bookmark-icon" width="18" height="19">
<use xlinkHref="#icon-bookmark"></use>
</svg>
Expand All @@ -21,14 +33,14 @@ function CityCard(): JSX.Element {
</div>
<div className="place-card__rating rating">
<div className="place-card__stars rating__stars">
<span style={{width: '80%'}}></span>
<span style={{width: `${(offer.rating / 5) * 100}%`}}></span>
<span className="visually-hidden">Rating</span>
</div>
</div>
<h2 className="place-card__name">
<a href="#">Canal View Prinsengracht</a>
<Link to={`/offer/${offer.id}`}>{offer.title}</Link>
</h2>
<p className="place-card__type">Apartment</p>
<p className="place-card__type">{offer.type}</p>
</div>
</article>
);
Expand Down
65 changes: 65 additions & 0 deletions src/components/comment-form/comment-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { useState } from 'react';

function CommentForm(): JSX.Element {
const [formData, setFormData] = useState({
rating: '1',
review: '',
});
const handleFieldChange = (evt: React.ChangeEvent<HTMLInputElement|HTMLTextAreaElement>): void => {
const {name, value} = evt.target;
setFormData({
...formData,
[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">
<input className="form__rating-input visually-hidden" name="rating" value="5" id="5-stars" type="radio" onChange={handleFieldChange}/>
<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" onChange={handleFieldChange}/>
<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" onChange={handleFieldChange}/>
<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" onChange={handleFieldChange}/>
<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" onChange={handleFieldChange}/>
<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" value={formData.review} onChange={handleFieldChange} 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>
);
}
export default CommentForm;
17 changes: 17 additions & 0 deletions src/components/offer-list/offer-list.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<div className="cities__places-list places__list tabs__content">
{offers.map((offer) => (
<CityCard key={offer.id} offer={offer}/>
))}
</div>
);
}
export default OfferList;
3 changes: 2 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ 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
);

root.render(
<React.StrictMode>
<App placesCount={Settings.placesCount} />
<App placesCount={Settings.placesCount} offers={offers}/>
</React.StrictMode>
);
49 changes: 49 additions & 0 deletions src/mocks/offers.ts
Original file line number Diff line number Diff line change
@@ -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]]
},
];
36 changes: 36 additions & 0 deletions src/mocks/reviews.ts
Original file line number Diff line number Diff line change
@@ -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.'
}
];
Loading

0 comments on commit d0e223b

Please sign in to comment.