Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Обратная сторона реальности #4

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 33 additions & 3 deletions src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
import {MainScreen} from './pages/MainScreen';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import MainScreen from './pages/MainScreen';
import Login from './pages/Login';
import Favorites from './pages/Favorites';
import Offer from './pages/Offer';
import NotFound from './NotFound';
import AppRoute, { AuthorizationStatus } from '../const';
import PrivateRoute from './private-route';
import { OffersType } from '../types/offer';

type AppScreenProps = {
placesCount: number;
offers: OffersType[];
favorites: OffersType[];
}
function App({placesCount}: AppScreenProps){
function App({placesCount, offers, favorites}: AppScreenProps){
return (
<MainScreen placesCount={placesCount}/>
<HelmetProvider>
<BrowserRouter>
<Routes>
<Route path ={AppRoute.Root} element = {<MainScreen placesCount={placesCount} offers={offers}/>} />
<Route path={AppRoute.Login} element={<Login/>}/>
<Route
path={AppRoute.Favorites}
element = {
<PrivateRoute
authorizationStatus={AuthorizationStatus.NoAuth}
>
<Favorites favorites={favorites}/>
</PrivateRoute>
}
/>
<Route path={AppRoute.Offer} element={<Offer/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</BrowserRouter>
</HelmetProvider>
);
}
export default App;
17 changes: 17 additions & 0 deletions src/components/Logo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Link } from 'react-router-dom';

function Logo(){
return(
<Link className="header__logo-link header__logo-link--active" to={'/'}>
<img
className="header__logo"
src="img/logo.svg"
alt="6 cities logo"
width={81}
height={41}
/>
</Link>
);
}

export default Logo;
12 changes: 12 additions & 0 deletions src/components/NotFound.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Link } from 'react-router-dom';

function NotFound() {
return (
<div>
<h1>404 Not Found</h1>
<Link to="/">Go to Home Page</Link>
</div>
);
}

export default NotFound;
120 changes: 120 additions & 0 deletions src/components/commentForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { useState } from 'react';

function CommentForm() {
const [text, setText] = useState('');
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"
defaultValue={5}
id="5-stars"
type="radio"
/>
<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" />
</svg>
</label>
<input
className="form__rating-input visually-hidden"
name="rating"
defaultValue={4}
id="4-stars"
type="radio"
/>
<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" />
</svg>
</label>
<input
className="form__rating-input visually-hidden"
name="rating"
defaultValue={3}
id="3-stars"
type="radio"
/>
<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" />
</svg>
</label>
<input
className="form__rating-input visually-hidden"
name="rating"
defaultValue={2}
id="2-stars"
type="radio"
/>
<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" />
</svg>
</label>
<input
className="form__rating-input visually-hidden"
name="rating"
defaultValue={1}
id="1-star"
type="radio"
/>
<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" />
</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"
onChange={(evt) => setText(evt.target.value)}
value={text}
>
</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={undefined}
onClick={(evt) => evt.preventDefault()}
>
Submit
</button>
</div>
</form>
);
}

export default CommentForm;
18 changes: 18 additions & 0 deletions src/components/favoritesList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { OffersType } from '../types/offer';
import Card from './pages/Card';

type FavoritesListProps = {
favorites: OffersType[];
};

function FavoritesList({ favorites }: FavoritesListProps) {
return (
<div className="favorites__places">
{favorites.map((favorite) => (
<Card key={favorite.id} offer={favorite} />
))}
</div>
);
}

export default FavoritesList;
18 changes: 18 additions & 0 deletions src/components/offersList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Card from './pages/Card';
import { OffersType } from '../types/offer';

interface OffersListProps {
offers: OffersType[];
}

function OffersList({ offers }: OffersListProps) {
return (
<div className="cities__places-list places__list tabs__content">
{offers.map((offer) => (
<Card key={offer.id} offer={offer} />
))}
</div>
);
}

export default OffersList;
113 changes: 59 additions & 54 deletions src/components/pages/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,67 @@
import React from 'react';
import { useState } from 'react';
import { OffersType } from '../../types/offer';
import { Link } from 'react-router-dom';

interface CardProps {
premium: boolean;
imageUrl: string;
price: string;
bookmarked: boolean;
rating: number;
title: string;
type: string;
}
type CardProps = {
offer: OffersType;
};

const Card: React.FC<CardProps> = ({ premium, imageUrl, price, bookmarked, rating, title, type }) => (
<article className="cities__card place-card">
{premium && (
<div className="place-card__mark">
<span>Premium</span>
</div>
)}
<div className="cities__image-wrapper place-card__image-wrapper">
<a href="#">
<img
className="place-card__image"
src={imageUrl}
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">{price}</b>
<span className="place-card__price-text">/night</span>
function Card({ offer }: CardProps) {
const { id, title, imageUrl, type, rating, price, favorite, premium } = offer;
const [, setActive] = useState('');
return (
<article
className="cities__card place-card"
onMouseOver={() => setActive(id.toString())}
>
{premium && (
<div className="place-card__mark">
<span>Premium</span>
</div>
<button
className={`place-card__bookmark-button button${bookmarked ? ' place-card__bookmark-button--active' : ''}`}
type="button"
>
<svg className="place-card__bookmark-icon" width={18} height={19}>
<use xlinkHref="#icon-bookmark" />
</svg>
<span className="visually-hidden">{bookmarked ? 'In bookmarks' : 'To bookmarks'}</span>
</button>
)}
<div className="cities__image-wrapper place-card__image-wrapper">
<a href="#">
<img
className="place-card__image"
src={imageUrl}
width="260"
height="200"
alt="Place image"
/>
</a>
</div>
<div className="place-card__rating rating">
<div className="place-card__stars rating__stars">
<span style={{ width: `${rating}%` }} />
<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 place-card__bookmark-button--active button"
type="button"
>
<svg className="place-card__bookmark-icon" width="18" height="19">
{favorite && <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: `${(rating / 5) * 100}%` }}></span>
<span className="visually-hidden">Rating</span>
</div>
</div>
<h2 className="place-card__name">
<Link to={`/offer/${id}`} state={offer}>
{title}
</Link>
</h2>
<p className="place-card__type">{type}</p>
</div>
<h2 className="place-card__name">
<a href="#">{title}</a>
</h2>
<p className="place-card__type">{type}</p>
</div>
</article>
);

</article>
);
}

export default Card;

Loading
Loading