Skip to content

Commit

Permalink
Merge pull request #4 from SixBlueBlack/module4-task1
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Jan 3, 2025
2 parents 057da37 + 2b7b4b5 commit 10651a8
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 203 deletions.
11 changes: 6 additions & 5 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@ import Favourites from '../pages/favourites.tsx';
import Offer from '../pages/offer.tsx';
import NotFound from '../pages/not_found.tsx';
import PrivateRoute from './private-route.tsx';
import {OfferCardType} from '../types/offer_card_type.ts';

type AppProps = {
offersNumber: number;
offerCards: OfferCardType[];
}

function App({offersNumber}: AppProps): JSX.Element {
function App({offerCards}: AppProps): JSX.Element {
return (
<BrowserRouter>
<Routes>
<Route path={AppRoute.Main} element={<MainScreen offersNumber={offersNumber}/>}/>
<Route path={AppRoute.Main} element={<MainScreen offerCards={offerCards}/>}/>
<Route path={AppRoute.Login} element={<Login/>}/>
<Route
path={AppRoute.Favourites}
element={
<PrivateRoute authorizationStatus={AuthorizationStatus.NoAuth}>
<Favourites/>
<PrivateRoute authorizationStatus={AuthorizationStatus.Auth}>
<Favourites favourites={offerCards}/>
</PrivateRoute>
}
/>
Expand Down
52 changes: 52 additions & 0 deletions src/components/favourite.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import {OfferCardType} from '../types/offer_card_type.ts';
import {Link} from 'react-router-dom';

type FavouriteCardProps = {
favourite: OfferCardType;
}

function Favourite({favourite}: FavouriteCardProps): JSX.Element {
return (
<article className="favorites__card place-card">
{favourite.isPremium && (
<div className="place-card__mark">
<span>Premium</span>
</div>
)}
<div className="favorites__image-wrapper place-card__image-wrapper">
<a href="#">
<img className="place-card__image" src={favourite.image} width="150" height="110"
alt="Place image"
>
</img>
</a>
</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;{favourite.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">
<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: `${favourite.rating * 20}%`}}></span>
<span className="visually-hidden">Rating</span>
</div>
</div>
<h2 className="place-card__name">
<Link to={`/offer/${favourite.id}`}>{favourite.title}</Link>
</h2>
<p className="place-card__type">{favourite.placeType}</p>
</div>
</article>
);
}

export default Favourite;
18 changes: 18 additions & 0 deletions src/components/favourite_list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {OfferCardType} from '../types/offer_card_type.ts';
import Favourite from './favourite.tsx';

type FavouriteListProps = {
favourites: OfferCardType[];
}

function FavouriteList({favourites}: FavouriteListProps): JSX.Element {
return (
<>
{
favourites.map((favourite) => <Favourite key={favourite.id} favourite={favourite}/>)
}
</>
);
}

export default FavouriteList;
29 changes: 20 additions & 9 deletions src/components/offer_card.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
function OfferCard(): JSX.Element {
import {OfferCardType} from '../types/offer_card_type.ts';
import {MouseEventHandler} from 'react';
import {Link} from 'react-router-dom';

type OfferCardProps = {
offerCard: OfferCardType;
mouseHandler: MouseEventHandler;
}

function OfferCard({offerCard, mouseHandler}: OfferCardProps): JSX.Element {
return (
<article className="cities__card place-card">
<div className="place-card__mark">
<span>Premium</span>
</div>
<article onMouseOver={mouseHandler} className="cities__card place-card">
{offerCard.isPremium && (
<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="img/apartment-01.jpg" width="260" height="200"
<img className="place-card__image" src={offerCard.image} width="260" height="200"
alt="Place image"
>
</img>
Expand All @@ -15,7 +26,7 @@ function OfferCard(): JSX.Element {
<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>
<b className="place-card__price-value">&euro;{offerCard.price}</b>
<span className="place-card__price-text">&#47;&nbsp;night</span>
</div>
<button className="place-card__bookmark-button button" type="button">
Expand All @@ -27,12 +38,12 @@ function OfferCard(): JSX.Element {
</div>
<div className="place-card__rating rating">
<div className="place-card__stars rating__stars">
<span style={{width: '80%'}}></span>
<span style={{width: `${offerCard.rating * 20}%`}}></span>
<span className="visually-hidden">Rating</span>
</div>
</div>
<h2 className="place-card__name">
<a href="#">Beautiful &amp; luxurious apartment at great location</a>
<Link to={`/offer/${offerCard.id}`}>{offerCard.title}</Link>
</h2>
<p className="place-card__type">Apartment</p>
</div>
Expand Down
28 changes: 28 additions & 0 deletions src/components/offer_card_list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {OfferCardType} from '../types/offer_card_type.ts';
import OfferCard from './offer_card.tsx';
import {MouseEventHandler, useState} from 'react';

type OfferCardListProps = {
offerCards: OfferCardType[];
}

function OfferCardList({offerCards}: OfferCardListProps): JSX.Element {
const [, setOfferCardActive] = useState(0);

return (
<>
{
offerCards.map((offer) => {
const mouseHandler: MouseEventHandler = () => {
setOfferCardActive(offer.id);
};

return (
<OfferCard key={offer.id} offerCard={offer} mouseHandler={mouseHandler}/>);
})
}
</>
);
}

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

const StarTitles: {[key: number]: string} = {
1: 'terrible',
2: 'bad',
3: 'not bad',
4: 'good',
5: 'perfect',
};

function Review(): JSX.Element {
const [reviewData, setReviewData] = useState({
review: '',
rating: 0
});

const handleChange = (event: ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
const {name, value} = event.target;
setReviewData({...reviewData, [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">
{Array.from({ length: 5 }, (_, index) => 5 - index).map((number) => (
<>
<input className="form__rating-input visually-hidden" name="rating" value={`${number}`} id={`${number}-stars`}
type="radio" onChange={handleChange}
>
</input>
<label htmlFor={`${number}-stars`} className="reviews__rating-label form__rating-label"
title={StarTitles[number]}
>
<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={reviewData.review}
placeholder="Tell how was your stay, what you like and what can be improved" onChange={handleChange}
>
</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
onClick={() => {}}
>Submit
</button>
</div>
</form>
);
}

export default Review;
6 changes: 4 additions & 2 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './components/app';
import {OfferCards} from './mocks/offer_cards';

const offersNumber = 10;
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);

root.render(
<React.StrictMode>
<App offersNumber={offersNumber}/>
<App
offerCards={OfferCards}
/>
</React.StrictMode>
);
40 changes: 40 additions & 0 deletions src/mocks/offer_cards.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {OfferCardType, PlaceType} from '../types/offer_card_type';

export const OfferCards: OfferCardType[] = [
{
id: 1,
title: 'Beautiful & luxurious studio at great location',
price: 210,
isPremium: true,
image: 'img/apartment-01.jpg',
rating: 1,
placeType: PlaceType.Apartment,
},
{
id: 2,
title: 'Wood and stone place',
price: 80,
isPremium: false,
image: 'img/room.jpg',
rating: 4,
placeType: PlaceType.Room,
},
{
id: 3,
title: 'Aboba',
price: 111,
isPremium: false,
image: 'img/apartment-02.jpg',
rating: 3,
placeType: PlaceType.Apartment,
},
{
id: 4,
title: 'Chetvertoe predlozenie',
price: 44,
isPremium: false,
image: 'img/apartment-03.jpg',
rating: 5,
placeType: PlaceType.Apartment,
}
];
Loading

0 comments on commit 10651a8

Please sign in to comment.