Skip to content

Commit

Permalink
Merge pull request #15 from mgmman/module9-task1
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Dec 11, 2024
2 parents a896a43 + 4c03d8b commit b29ed1b
Show file tree
Hide file tree
Showing 40 changed files with 570 additions and 88 deletions.
4 changes: 2 additions & 2 deletions src/Pages/login-page/login-page-right-section.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from 'react-router-dom';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import { changeCity } from '../../store/offers/offers.slice.ts';
import { CITIES } from '../../consts/cities.ts';
import { useAppDispatch } from '../../store/store.ts';
Expand All @@ -13,7 +13,7 @@ function LoginPageRightSectionImpl() {
<div className="locations__item">
<Link
className="locations__item-link"
to={AppRoutes.MainPage}
to={AppRoute.MainPage}
onClick={() => dispatch(changeCity(city))}
>
<span>{city.name}</span>
Expand Down
1 change: 0 additions & 1 deletion src/Pages/login-page/login-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export function LoginPage(): React.JSX.Element {
loginInfo.email &&
validateEmail(loginInfo.email) &&
loginInfo.password &&
loginInfo.password.length > 3 &&
loginInfo.password.match(/[a-zA-z]/g) &&
loginInfo.password.match(/[0-9]/g);
return (
Expand Down
8 changes: 4 additions & 4 deletions src/Pages/not-found-page/not-found-page.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Link } from 'react-router-dom';
import { Helmet } from 'react-helmet-async';
import {AppRoutes} from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';

export function NotFoundPage(): React.JSX.Element {
return (
<main className='not-found-page'>
<main className="not-found-page">
<Helmet>
<title>404 - not found</title>
</Helmet>
<h1>404 - Page Not Found</h1>
<p className='not-found-page__title'>
<p className="not-found-page__title">
The page you are looking for might have been removed or is temporarily
unavailable.
</p>
<Link to={AppRoutes.MainPage} className='not-found-page__link'>
<Link to={AppRoute.MainPage} className="not-found-page__link">
back to main page
</Link>
</main>
Expand Down
4 changes: 2 additions & 2 deletions src/Pages/offer-page/offer-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { OfferGallery } from '../../components/offer/offer-gallery.tsx';
import { BookmarkButton } from '../../components/bookmark-button.tsx';
import { store, useAppSelector } from '../../store/store.ts';
import { Spinner } from '../../components/spinner/Spinner.tsx';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import {
fetchNearbyOffers,
fetchOffer,
Expand All @@ -38,7 +38,7 @@ export function OfferPage(): React.JSX.Element {
const currentOffer = useAppSelector(getCurrentOffer);
const currentReviews = useAppSelector(getCurrentReviews);
if (currentOffer === undefined) {
return <Navigate to={AppRoutes.NotFoundPage} />;
return <Navigate to={AppRoute.NotFoundPage} />;
}
return (
<div className="page">
Expand Down
26 changes: 24 additions & 2 deletions src/api/api.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
import axios, { AxiosInstance, InternalAxiosRequestConfig } from 'axios';
import axios, {
AxiosError,
AxiosInstance,
InternalAxiosRequestConfig,
} from 'axios';
import { getToken } from '../utils/token-utils.ts';
import { toast } from 'react-toastify';

const BACKEND_URL = 'https://14.design.htmlacademy.pro/six-cities';
const REQUEST_TIMEOUT = 5000;
const REQUEST_TIMEOUT = 3000;

export const createAPI = (): AxiosInstance => {
const api = axios.create({
Expand All @@ -20,5 +25,22 @@ export const createAPI = (): AxiosInstance => {
return config;
});

api.interceptors.response.use(
(response) => response,
(error: AxiosError) => {
if (
error &&
(error.code === 'ECONNABORTED' || error.code === 'ERR_NETWORK')
) {
toast.error(
'Сервер недоступен, проверте подключение к интернету или повторите попытку позже',
{
toastId: 'server-unreachable',
},
);
}
},
);

return api;
};
14 changes: 7 additions & 7 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
AuthorizationWrapperForAuthorizedOnly,
AuthorizationWrapperForUnauthorizedOnly,
} from './authorization-wrapper.tsx';
import { AppRoutes } from '../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../dataTypes/enums/app-route.ts';
import { HelmetProvider } from 'react-helmet-async';
import { Provider } from 'react-redux';
import { store } from '../store/store.ts';
Expand All @@ -19,28 +19,28 @@ export function App(): React.JSX.Element {
<HelmetProvider>
<BrowserRouter>
<Routes>
<Route path={AppRoutes.MainPage} element={<MainPage />} />
<Route path={AppRoute.MainPage} element={<MainPage />} />
<Route
path={AppRoutes.Login}
path={AppRoute.Login}
element={
<AuthorizationWrapperForUnauthorizedOnly
fallbackUrl={AppRoutes.MainPage}
fallbackUrl={AppRoute.MainPage}
>
<LoginPage />
</AuthorizationWrapperForUnauthorizedOnly>
}
/>
<Route
path={AppRoutes.Favorites}
path={AppRoute.Favorites}
element={
<AuthorizationWrapperForAuthorizedOnly
fallbackUrl={AppRoutes.Login}
fallbackUrl={AppRoute.Login}
>
<FavoritesPage />
</AuthorizationWrapperForAuthorizedOnly>
}
/>
<Route path={`${AppRoutes.Offer}/:id`} element={<OfferPage />} />
<Route path={`${AppRoute.Offer}/:id`} element={<OfferPage />} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</BrowserRouter>
Expand Down
4 changes: 2 additions & 2 deletions src/components/authorization-wrapper.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Navigate } from 'react-router-dom';
import { useAppSelector } from '../store/store.ts';
import { AppRoutes } from '../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../dataTypes/enums/app-route.ts';
import { getIsAuthorized } from '../store/user/user.selectors.ts';

interface AuthorizationWrapperProps {
children: React.JSX.Element;
fallbackUrl: AppRoutes;
fallbackUrl: AppRoute;
}

export function AuthorizationWrapperForAuthorizedOnly({
Expand Down
4 changes: 2 additions & 2 deletions src/components/bookmark-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { bookmarkOffer } from '../store/async-actions.ts';
import { Offer } from '../dataTypes/offer.ts';
import { getIsAuthorized } from '../store/user/user.selectors.ts';
import { useNavigate } from 'react-router-dom';
import { AppRoutes } from '../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../dataTypes/enums/app-route.ts';

interface BookmarkButtonProps {
size: 'big' | 'small';
Expand Down Expand Up @@ -45,7 +45,7 @@ export function BookmarkButton({
);
setIsFavoriteReactive(!isFavoriteReactive);
} else {
navigate(AppRoutes.Login);
navigate(AppRoute.Login);
}
}}
>
Expand Down
4 changes: 2 additions & 2 deletions src/components/layout/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Link } from 'react-router-dom';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import { memo } from 'react';

function FooterImpl() {
return (
<footer className="footer container">
<Link className="footer__logo-link" to={AppRoutes.MainPage}>
<Link className="footer__logo-link" to={AppRoute.MainPage}>
<img
className="footer__logo"
src="img/logo.svg"
Expand Down
6 changes: 3 additions & 3 deletions src/components/layout/header.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from 'react-router-dom';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import { useAppSelector } from '../../store/store.ts';
import { memo } from 'react';
import { UserInfo } from './user-info.tsx';
Expand All @@ -16,7 +16,7 @@ function HeaderImpl({ dontShowUserInfo }: HeaderProps) {
<div className="container">
<div className="header__wrapper">
<div className="header__left">
<Link className="header__logo-link" to={AppRoutes.MainPage}>
<Link className="header__logo-link" to={AppRoute.MainPage}>
<img
className="header__logo"
src="img/logo.svg"
Expand All @@ -35,7 +35,7 @@ function HeaderImpl({ dontShowUserInfo }: HeaderProps) {
<li className="header__nav-item user">
<Link
className="header__nav-link header__nav-link--profile"
to={AppRoutes.Login}
to={AppRoute.Login}
>
<div className="header__avatar-wrapper user__avatar-wrapper"></div>
<span className="header__login">Sign in</span>
Expand Down
6 changes: 3 additions & 3 deletions src/components/layout/user-info.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link, useNavigate } from 'react-router-dom';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import { useAppDispatch, useAppSelector } from '../../store/store.ts';
import { logout } from '../../store/async-actions.ts';
import { memo } from 'react';
Expand All @@ -15,15 +15,15 @@ function UserInfoImpl() {
const handleLogout = () => {
dispatch(logout());
dispatch(setFavoriteOffers([]));
navigate(AppRoutes.MainPage);
navigate(AppRoute.MainPage);
};
return (
<nav className="header__nav">
<ul className="header__nav-list">
<li className="header__nav-item user">
<Link
className="header__nav-link header__nav-link--profile"
to={AppRoutes.Favorites}
to={AppRoute.Favorites}
>
<div className="header__avatar-wrapper user__avatar-wrapper">
{userInfo?.avatarUrl && (
Expand Down
6 changes: 3 additions & 3 deletions src/components/offer/offer-card.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Link } from 'react-router-dom';
import { AppRoutes } from '../../dataTypes/enums/app-routes.ts';
import { AppRoute } from '../../dataTypes/enums/app-route.ts';
import cn from 'classnames';
import { Rating } from '../rating.tsx';
import { BookmarkButton } from '../bookmark-button.tsx';
Expand Down Expand Up @@ -54,7 +54,7 @@ export function OfferCardImpl({
{ 'near-places__image-wrapper': !isOnMainPage },
)}
>
<Link to={`${AppRoutes.Offer}/${id}`}>
<Link to={`${AppRoute.Offer}/${id}`}>
<img
className="place-card__image"
src={previewImage}
Expand All @@ -79,7 +79,7 @@ export function OfferCardImpl({
</div>
<Rating rating={rating} usePlace="place-card" />
<h2 className="place-card__name">
<Link to={`${AppRoutes.Offer}/${id}`}>{title}</Link>
<Link to={`${AppRoute.Offer}/${id}`}>{title}</Link>
</h2>
<p className="place-card__type">{capitalize(type)}</p>
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/components/reviews/review-component.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getFirstName } from '../../utils/username-utils.ts';
import { Rating } from '../rating.tsx';
import { formatDate } from '../../utils/date-utils.ts';

interface ReviewProps {
comment: string;
Expand Down Expand Up @@ -34,7 +35,7 @@ export function ReviewComponent({
<Rating rating={rating} usePlace="reviews" />
<p className="reviews__text">{comment}</p>
<time className="reviews__time" dateTime={date.toDateString()}>
{date.toLocaleDateString('en-US', {})}
{formatDate(date)}
</time>
</div>
</li>
Expand Down
6 changes: 5 additions & 1 deletion src/components/reviews/review-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ export function ReviewForm(): React.JSX.Element {
const offerId = useAppSelector(getCurrentOffer)!.id;
const reviewPostingStatus = useAppSelector(getReviewPostingStatus);
useEffect(() => {
if (reviewPostingStatus === ReviewStatus.Success) {
let isMounted = true;
if (isMounted && reviewPostingStatus === ReviewStatus.Success) {
setReview({ comment: '', rating: undefined });
}
return () => {
isMounted = false;
};
}, [reviewPostingStatus]);
const onRatingChange: React.ChangeEventHandler<HTMLInputElement> = (
event,
Expand Down
6 changes: 4 additions & 2 deletions src/components/reviews/reviews-list.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Review } from '../../dataTypes/review.ts';
import { ReviewComponent } from './review-component.tsx';
import { useAppSelector } from '../../store/store.ts';
import { getReviewsCount } from '../../store/current-offer/current-offer.selectors.ts';

interface ReviewsListProps {
reviews: Review[];
}

export function ReviewsList({ reviews }: ReviewsListProps): React.JSX.Element {
const reviewsCount = useAppSelector(getReviewsCount);
return (
<>
<h2 className="reviews__title">
Reviews &middot;{' '}
<span className="reviews__amount">{reviews.length}</span>
Reviews &middot; <span className="reviews__amount">{reviewsCount}</span>
</h2>
<ul className="reviews__list">
{reviews.map((review: Review) => (
Expand Down
9 changes: 6 additions & 3 deletions src/components/reviews/reviews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Review } from '../../dataTypes/review.ts';
import { useAppSelector } from '../../store/store.ts';
import { useMemo } from 'react';
import { getIsAuthorized } from '../../store/user/user.selectors.ts';
import { MAX_REVIEWS_COUNT } from '../../consts/reviews.ts';

interface ReviewsProps {
reviews: Review[];
Expand All @@ -12,9 +13,11 @@ interface ReviewsProps {
export function Reviews({ reviews }: ReviewsProps): React.JSX.Element {
const sortedReviews = useMemo(
() =>
reviews.toSorted(
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(),
),
reviews
.toSorted(
(a, b) => new Date(b.date).getTime() - new Date(a.date).getTime(),
)
.slice(0, MAX_REVIEWS_COUNT),
[reviews],
);
const isAuthorized = useAppSelector(getIsAuthorized);
Expand Down
2 changes: 1 addition & 1 deletion src/consts/cities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 +61,4 @@ export const CITIES: City[] = [
AMSTERDAM,
HAMBURG,
DUSSELDORF,
];
] as const;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum ApiRoutes {
export enum ApiRoute {
Offers = '/offers',
Login = '/login',
Logout = '/logout',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum AppRoutes {
export enum AppRoute {
MainPage = '/',
Login = '/login',
Offer = '/offer',
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum NameSpaces {
export enum NameSpace {
Offers = 'Offers',
CurrentOffer = 'CurrentOffer',
User = 'User',
Expand Down
Loading

0 comments on commit b29ed1b

Please sign in to comment.