Skip to content
Closed
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
12 changes: 10 additions & 2 deletions src/components/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Routes, Route} from 'react-router-dom';
import {AppRoute, RequestStatus} from '../../const';
import {useAppSelector} from '../../hooks/types';
import {getAllOffersStatus} from '../../store/app-data/app-data.selectors';
import {getAuthStatus} from '../../store/user-process/user-process.selectors';
import {getAuthStatus, getAuthorizationStatus} from '../../store/user-process/user-process.selectors';
import HistoryRouter from '../history-route/history-route';
import browserHistory from '../../browser-history';
import PrivateRoute from '../private-route/private-route';
Expand All @@ -12,10 +12,12 @@ import LoginPage from '../../pages/login-page/login-page';
import NotFoundPage from '../../pages/not-found-page/not-found-page';
import OfferPage from '../../pages/offer-page/offer-page';
import LoadingPage from '../../pages/loading-page/loading-page';
import PublicRoute from '../public-route/public-route';

function App(): JSX.Element {
const allOffersStatus = useAppSelector(getAllOffersStatus);
const isUserAuth = useAppSelector(getAuthStatus);
const authorizationStatus = useAppSelector(getAuthorizationStatus);

if (!isUserAuth || allOffersStatus === RequestStatus.Loading) {
return (
Expand All @@ -42,7 +44,13 @@ function App(): JSX.Element {
/>
<Route
path={AppRoute.Login}
element={<LoginPage />}
element={
<PublicRoute
authorizationStatus={authorizationStatus}
>
<LoginPage />
</PublicRoute>
}
/>
<Route
path="*"
Expand Down
9 changes: 6 additions & 3 deletions src/components/place-card/place-card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {Link} from 'react-router-dom';
import {Offer} from '../../types/offer';
import {capitalizeFirst} from '../../utils';
import {PlaceCardClass} from '../../const';
import {useLocation} from 'react-router-dom';

const STARS_STYLE_COEFF = 20;

Expand All @@ -19,7 +20,9 @@ function PlaceCard({
placeCardClass
}: PlaceCardProps): JSX.Element {

const isFavorite = placeCardClass === PlaceCardClass.Favorites;
const location = useLocation();
const isFavorite = offer.isFavorite;
const isFavoritePage = !!location.pathname.includes('/favorites');

const {isPremium, previewImage, id, price, rating, title, type} = offer;

Expand All @@ -34,8 +37,8 @@ function PlaceCard({
<img
className="place-card__image"
src={previewImage}
width={isFavorite ? '150' : '260'}
height={isFavorite ? '110' : '200'}
width={isFavorite && isFavoritePage ? '150' : '260'}
height={isFavorite && isFavoritePage ? '110' : '200'}
alt="Place image"
/>
</Link>
Expand Down
19 changes: 19 additions & 0 deletions src/components/public-route/public-route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Navigate} from 'react-router-dom';
import {AppRoute, AuthorizationStatus} from '../../const';

type PublicRouteProps = {
authorizationStatus: AuthorizationStatus;
children: JSX.Element;
}

function PublicRoute(props: PublicRouteProps): JSX.Element {
const {authorizationStatus, children} = props;

return (
authorizationStatus !== AuthorizationStatus.Auth
? children
: <Navigate to={AppRoute.Main} />
);
}

export default PublicRoute;
28 changes: 28 additions & 0 deletions src/components/random-city/random-city.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import {CITIES} from '../../const';
import {Link} from 'react-router-dom';
import {changeActiveCity} from '../../store/app-process/app-process';
import {useAppDispatch} from '../../hooks/types';
import {getRandomInteger} from '../../utils';
import {AppRoute} from '../../const';

function RandomCity(): JSX.Element {
const dispatch = useAppDispatch();
const randomCityIndex = getRandomInteger(0, CITIES.length - 1);
const randomCity = CITIES[randomCityIndex];

return (
<section className="locations locations--login locations--current">
<div className="locations__item">
<Link
className="locations__item-link"
to={AppRoute.Main}
onClick={() => dispatch(changeActiveCity({activeCity: randomCity}))}
>
<span>{randomCity.name}</span>
</Link>
</div>
</section>
);
}

export default RandomCity;
13 changes: 9 additions & 4 deletions src/components/reviews-form/reviews-form.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useState, Fragment, FormEvent} from 'react';
import {useState, Fragment, FormEvent, ChangeEvent} from 'react';
import {FullOffer} from '../../types/offer';
import {reviewsActions} from '../../store/reviews-data/reviews-data';
import {useActionCreators} from '../../hooks/types';
Expand Down Expand Up @@ -33,7 +33,12 @@ function ReviewsForm({offerId}: ReviewsFormProps): JSX.Element {
isformDisabled: false
});

const handleChange = (evt: {target: {name: string; value: string}}) => {
const handleRatingChange = (evt: ChangeEvent<HTMLInputElement>) => {
const {name, value} = evt.target;
setUserReview({...userReview, [name]: value});
};

const handleTextChange = (evt: ChangeEvent<HTMLTextAreaElement>) => {
const {name, value} = evt.target;
setUserReview({...userReview, [name]: value});
};
Expand Down Expand Up @@ -89,7 +94,7 @@ function ReviewsForm({offerId}: ReviewsFormProps): JSX.Element {
value={value}
id={`${value}-stars`}
type="radio"
onChange={handleChange}
onInput={handleRatingChange}
disabled={isformDisabled}
/>
<label htmlFor={`${value}-stars`} className="reviews__rating-label form__rating-label" title={label}>
Expand All @@ -108,7 +113,7 @@ function ReviewsForm({offerId}: ReviewsFormProps): JSX.Element {
required
disabled={isformDisabled}
placeholder="Tell how was your stay, what you like and what can be improved"
onChange={handleChange}
onChange={handleTextChange}
>

</textarea>
Expand Down
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const root = ReactDOM.createRoot(
root.render(
<React.StrictMode>
<Provider store = {store}>
<ToastContainer />
<ToastContainer autoClose={1000} />
<App />
</Provider>
</React.StrictMode>
Expand Down
10 changes: 2 additions & 8 deletions src/pages/login-page/login-page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Logo from '../../components/logo/logo';
import {Link} from 'react-router-dom';
import {useRef, FormEvent} from 'react';
import {useAppDispatch} from '../../hooks/types';
import {login} from '../../store/api-actions';
import RandomCity from '../../components/random-city/random-city';

function LoginPage(): JSX.Element {
const emailRef = useRef<HTMLInputElement | null>(null);
Expand Down Expand Up @@ -75,13 +75,7 @@ function LoginPage(): JSX.Element {
</button>
</form>
</section>
<section className="locations locations--login locations--current">
<div className="locations__item">
<Link className="locations__item-link" to="#">
<span>Amsterdam</span>
</Link>
</div>
</section>
<RandomCity />
</div>
</main>
</div>
Expand Down
50 changes: 26 additions & 24 deletions src/pages/main-page/main-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,37 +50,39 @@ function MainPage(): JSX.Element {
<Header />
</header>

<main className={`page__main page__main--index ${offers.length === 0 && 'page__main--index-empty'}`}>
<main className={`page__main page__main--index ${activeCityOffers.length === 0 ? 'page__main--index-empty' : ''}`}>
<h1 className="visually-hidden">Cities</h1>
<div className="tabs">
<section className="locations container">
<CitiesList citiesList={CITIES} />
</section>
</div>
<div className="cities">
{offers.length === 0 ?
<MainEmpty activeCityName={activeCity.name} />
:
<div className="cities__places-container container">
<section className="cities__places places">
<h2 className="visually-hidden">Places</h2>
<b className="places__found">{activeCityOffers.length} place{(activeCityOffers.length > 1 || activeCityOffers.length === 0) && 's'} to stay in {activeCity.name}</b>
{activeCityOffers.length > 0 && <PlacesSorting current={activeSort} setter={setActiveSort} />}
<div className="cities__places-list places__list tabs__content">
<OffersList
onHandleChangeActiveId={handleChangeActiveId}
offers={sortedOffers}
/>
</div>
</section>
<div className="cities__right-section">
<CitiesMap
city={activeCity}
offers={activeCityOffers}
activeOfferId={activeOfferId}
/>
</div>
</div>}
<div className={`cities__places-container ${(activeCityOffers.length === 0) ? 'cities__places-container--empty' : ''} container`}>
{(activeCityOffers.length === 0) && <MainEmpty activeCityName={activeCity.name} />}
{(activeCityOffers.length > 0) &&
<>
<section className="cities__places places">
<h2 className="visually-hidden">Places</h2>
<b className="places__found">{activeCityOffers.length} place{(activeCityOffers.length > 1 || activeCityOffers.length === 0) && 's'} to stay in {activeCity.name}</b>
{activeCityOffers.length > 0 && <PlacesSorting current={activeSort} setter={setActiveSort} />}
<div className="cities__places-list places__list tabs__content">
<OffersList
onHandleChangeActiveId={handleChangeActiveId}
offers={sortedOffers}
/>
</div>
</section>
<div className="cities__right-section">
{activeCityOffers.length === 0 ? '' :
<CitiesMap
city={activeCity}
offers={activeCityOffers}
activeOfferId={activeOfferId}
/>}
</div>
</>}
</div>
</div>
</main>
</div>
Expand Down
9 changes: 7 additions & 2 deletions src/pages/offer-page/offer-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {RequestStatus} from '../../const';
import {sortReviewsByDate} from '../../utils';
import LoadingPage from '../loading-page/loading-page';
import NotFoundPage from '../not-found-page/not-found-page';
import {Offer} from '../../types/offer';

const MAX_REVIEWS = 10;
const MAX_COUNT_NEARBY_OFFERS = 3;
Expand All @@ -26,8 +27,12 @@ function OfferPage(): JSX.Element {
const reviews = useAppSelector(getReviews);

const sortedReviews = reviews.toSorted(sortReviewsByDate).slice(0, MAX_REVIEWS);
const slicedNearbyOffers = nearbyOffers && nearbyOffers.slice(0, MAX_COUNT_NEARBY_OFFERS);
const sortedOffers = [fullOffer, ...slicedNearbyOffers];
const slicedNearbyOffers = Array.isArray(nearbyOffers)
? nearbyOffers.slice(0, MAX_COUNT_NEARBY_OFFERS)
: [];
const sortedOffers = [fullOffer, ...slicedNearbyOffers].filter(
(offer): offer is Offer => Boolean(offer)
);

const {fetchFullOffer, fetchNearbyOffers, clearFullOffer, setActiveOfferId} = useActionCreators(fullOfferActions);
const {fetchReviews} = useActionCreators(reviewsActions);
Expand Down
7 changes: 7 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ export const capitalizeFirst = (string: string) => {
export function sortReviewsByDate(a: Review, b: Review) {
return new Date(b.date).getTime() - new Date(a.date).getTime();
}

export const getRandomInteger = (min: number, max: number) => {
const lower = Math.ceil(Math.min(min, max));
const upper = Math.floor(Math.max(min, max));
const result = Math.random() * (upper - lower + 1) + lower;
return Math.floor(result);
};