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

Добро пожаловать, или посторонним вход воспрещён (часть 1) #10

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
5 changes: 5 additions & 0 deletions src/browser-history.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {createBrowserHistory} from 'history';

const browserHistory = createBrowserHistory();

export default browserHistory;
24 changes: 13 additions & 11 deletions src/components/app/app.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import MainScreen from '../../pages/main-screen/main-screen';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import { 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';
Expand All @@ -8,35 +8,37 @@ import PrivateRoute from '../private-route/private-route.tsx';
import { AppRoute, AuthorizationStatus } from '../../const.ts';
import { useAppSelector } from '../../hooks/index.ts';
import LoadingScreen from '../../pages/loading-screen/loading-screen.tsx';
import HistoryRouter from '../history-route/history-route.tsx';
import browserHistory from '../../browser-history.ts';


function App(): JSX.Element {

const isQuestionsDataLoading = useAppSelector((state) => state.isQuestionsDataLoading);
const isOffersDataLoading = useAppSelector((state) => state.isOffersDataLoading);
const authorizationStatus = useAppSelector((state) => state.authorizationStatus);

if (isQuestionsDataLoading) {
if (isOffersDataLoading || authorizationStatus === AuthorizationStatus.Unknown) {
return (
<LoadingScreen />
);
}

return (
<BrowserRouter>
<HistoryRouter history={browserHistory}>
<Routes>
<Route path="*" element={<NotFoundScreen/>} />
<Route path={AppRoute.Main} element={<MainScreen/>} />
<Route path="*" element={<NotFoundScreen />} />
<Route path={AppRoute.Main} element={<MainScreen />} />
<Route
path={AppRoute.Favorites}
element={
<PrivateRoute authorizationStatus={AuthorizationStatus.Auth} >
<PrivateRoute >
<FavoritesScreen />
</PrivateRoute>
}
/>
<Route path={AppRoute.Login} element={<LoginScreen/>} />
<Route path={AppRoute.Offer} element={<OfferScreen/>} />
<Route path={AppRoute.Login} element={<LoginScreen />} />
<Route path={AppRoute.Offer} element={<OfferScreen />} />
</Routes>
</BrowserRouter>
</HistoryRouter>
);
}
export default App;
23 changes: 23 additions & 0 deletions src/components/header/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { Link } from 'react-router-dom';
import LoginNavigation from '../login-navigation/login-navigation';
import { AppRoute } from '../../const';

function Header(): JSX.Element {
return (
<header className="header">
<div className="container">
<div className="header__wrapper">
<div className="header__left">
<Link to={AppRoute.Main} className="header__logo-link header__logo-link--active">
<img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41" />
</Link>
</div>
<LoginNavigation />
</div>
</div>
</header>
);
}

export default Header;

35 changes: 35 additions & 0 deletions src/components/history-route/history-route.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {useState, useLayoutEffect} from 'react';
import {Router} from 'react-router-dom';
import type {BrowserHistory} from 'history';

export interface HistoryRouterProps {
history: BrowserHistory;
basename?: string;
children?: React.ReactNode;
}

function HistoryRouter({
basename,
children,
history,
}: HistoryRouterProps) {
const [state, setState] = useState({
action: history.action,
location: history.location,
});

useLayoutEffect(() => history.listen(setState), [history]);

return (
<Router
basename={basename}
location={state.location}
navigationType={state.action}
navigator={history}
>
{children}
</Router>
);
}

export default HistoryRouter;
48 changes: 48 additions & 0 deletions src/components/login-navigation/login-navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Link } from 'react-router-dom';
import { logoutAction } from '../../store/api-actions';
import { useAppDispatch, useAppSelector } from '../../hooks';
import { AppRoute, AuthorizationStatus } from '../../const';

function HeaderNavigation(): JSX.Element {
const dispatch = useAppDispatch();
const offers = useAppSelector((state) => state.offers);
const favoriteOffers = offers.filter((offer) => offer.isFavorite);
const userData = useAppSelector((state) => state.userData);
const authorizationStatus = useAppSelector((state) => state.authorizationStatus);
const handleSignOut = () => {
dispatch(logoutAction());
};
return (
<nav className="header__nav">
{authorizationStatus === AuthorizationStatus.Auth ? (
<ul className="header__nav-list">
<li className="header__nav-item user">
<Link to={AppRoute.Favorites} className="header__nav-link header__nav-link--profile" >
<div className="header__avatar-wrapper user__avatar-wrapper">
</div>
<span className="header__user-name user__name">{userData?.email}</span>
<span className="header__favorite-count">{favoriteOffers.length}</span>
</Link>
</li>
<li className="header__nav-item">
<Link to={AppRoute.Login} className="header__nav-link" onClick={handleSignOut}>
<span className="header__signout">Sign out</span>
</Link>
</li>
</ul>
) : (
<ul className="header__nav-list">
<li className="header__nav-item user">
<Link to={AppRoute.Login} className="header__nav-link header__nav-link--profile" >
<div className="header__avatar-wrapper user__avatar-wrapper">
</div>
<span className="header__login">Sign in</span>
</Link>
</li>
</ul>
)}
</nav>
);
}

export default HeaderNavigation;
5 changes: 3 additions & 2 deletions src/components/private-route/private-route.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {Navigate} from 'react-router-dom';
import { AppRoute, AuthorizationStatus } from '../../const';
import { useAppSelector } from '../../hooks';

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

function PrivateRoute(props: PrivateRouteProps): JSX.Element {
const {authorizationStatus, children} = props;
const {children} = props;
const authorizationStatus = useAppSelector((state) => state.authorizationStatus);
return (
authorizationStatus === AuthorizationStatus.Auth ? children : <Navigate to={AppRoute.Login}/>
);
Expand Down
14 changes: 8 additions & 6 deletions src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export const URL_MARKER_STANDART =

export enum APIRoute {
Offers = '/offers',
Login = '/login',
Logout = '/logout'
}

export const CITIES: City[] = [
Expand All @@ -29,47 +31,47 @@ export const CITIES: City[] = [
location: {
latitude: 48.864716,
longitude: 2.349014,
zoom: 11,
zoom: 13,
},
},
{
name: 'Brussels',
location: {
latitude: 50.85034,
longitude: 4.35171,
zoom: 11,
zoom: 13,
},
},
{
name: 'Cologne',
location: {
latitude: 50.935173,
longitude: 6.953101,
zoom: 11,
zoom: 13,
},
},
{
name: 'Amsterdam',
location: {
latitude: 52.3740300,
longitude: 4.8896900,
zoom: 11,
zoom: 13,
},
},
{
name: 'Hamburg',
location: {
latitude: 53.551086,
longitude: 9.993682,
zoom: 11,
zoom: 13,
},
},
{
name: 'Dusseldorf',
location: {
latitude: 51.233334,
longitude: 6.783333,
zoom: 11,
zoom: 13,
},
},
];
Expand Down
3 changes: 2 additions & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import ReactDOM from 'react-dom/client';
import App from './components/app/app';
import { Provider } from 'react-redux';
import { store } from './store';
import { fetchOffersAction } from './store/api-actions';
import { checkAuthAction, fetchOffersAction } from './store/api-actions';
import ErrorMessage from './components/error-message/error-message';

store.dispatch(fetchOffersAction());
store.dispatch(checkAuthAction());

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
Expand Down
36 changes: 5 additions & 31 deletions src/pages/favorites-screen/favorites-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,41 +2,15 @@ import { Link } from 'react-router-dom';
import { typeOfCardList } from '../../utils';
import OfferList from '../../components/offer-list/offer-list';
import { useAppSelector } from '../../hooks';
import Header from '../../components/header/header';
import { AppRoute } from '../../const';


function FavoritesScreen(): JSX.Element {
const favoriteOffers = useAppSelector((state) => state.offers).filter((offer) => offer.isFavorite);
return (
<div className="page">
<header className="header">
<div className="container">
<div className="header__wrapper">
<div className="header__left">
<Link to="/" className="header__logo-link">
<img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41"/>
</Link>
</div>
<nav className="header__nav">
<ul className="header__nav-list">
<li className="header__nav-item user">
<a className="header__nav-link header__nav-link--profile" href="#">
<div className="header__avatar-wrapper user__avatar-wrapper">
</div>
<span className="header__user-name user__name">[email protected]</span>
<span className="header__favorite-count">3</span>
</a>
</li>
<li className="header__nav-item">
<a className="header__nav-link" href="#">
<span className="header__signout">Sign out</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</header>

<Header />
<main className="page__main page__main--favorites">
<div className="page__favorites-container container">
<section className="favorites">
Expand All @@ -57,8 +31,8 @@ function FavoritesScreen(): JSX.Element {
</div>
</main>
<footer className="footer container">
<Link to="/" className="header__logo-link">
<img className="footer__logo" src="img/logo.svg" alt="6 cities logo" width="64" height="33"/>
<Link to={AppRoute.Main} className="header__logo-link">
<img className="footer__logo" src="img/logo.svg" alt="6 cities logo" width="64" height="33" />
</Link>
</footer>
</div>
Expand Down
38 changes: 30 additions & 8 deletions src/pages/login-screen/login-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,52 @@
import { FormEvent, useRef } from 'react';
import { AppRoute } from '../../const';
import { loginAction } from '../../store/api-actions';
import { useAppDispatch } from '../../hooks';
import { Link } from 'react-router-dom';

function LoginScreen(): JSX.Element {
const emailRef = useRef<HTMLInputElement | null>(null);
const passwordRef = useRef<HTMLInputElement | null>(null);

const dispatch = useAppDispatch();

const handleSubmit = (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();
if (emailRef.current !== null && passwordRef.current !== null) {
dispatch(
loginAction({
email: emailRef.current.value,
password: passwordRef.current.value
})
);
}
};
return (
<div className="page page--gray page--login">
<header className="header">
<div className="container">
<div className="header__wrapper">
<div className="header__left">
<a className="header__logo-link" href="main.html">
<img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41"/>
</a>
<Link to={AppRoute.Main} className="header__logo-link">
<img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41" />
</Link>
</div>
</div>
</div>
</header>
</header >

<main className="page__main page__main--login">
<div className="page__login-container container">
<section className="login">
<h1 className="login__title">Sign in</h1>
<form className="login__form form" action="#" method="post">
<form className="login__form form" action="#" method="post" onSubmit={handleSubmit}>
<div className="login__input-wrapper form__input-wrapper">
<label className="visually-hidden">E-mail</label>
<input className="login__input form__input" type="email" name="email" placeholder="Email" required/>
<input className="login__input form__input" type="email" name="email" placeholder="Email" required ref={emailRef} />
</div>
<div className="login__input-wrapper form__input-wrapper">
<label className="visually-hidden">Password</label>
<input className="login__input form__input" type="password" name="password" placeholder="Password" required/>
<input className="login__input form__input" type="password" name="password" placeholder="Password" required ref={passwordRef} />
</div>
<button className="login__submit form__submit button" type="submit">Sign in</button>
</form>
Expand All @@ -38,7 +60,7 @@ function LoginScreen(): JSX.Element {
</section>
</div>
</main>
</div>
</div >
);
}
export default LoginScreen;
Loading
Loading