Skip to content

Commit

Permalink
hw 7.3
Browse files Browse the repository at this point in the history
  • Loading branch information
ktvtk committed Nov 24, 2024
1 parent 1b3213d commit 659dd43
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 68 deletions.
24 changes: 22 additions & 2 deletions src/components/review-form/review-form.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import React, {JSX} from 'react';
import {useState} from 'react';
import {minCommentLength, maxCommentLength} from '../../const.ts';
import {store} from '../../store';
import {sendReview} from '../../store/api-actions.ts';
import {useAppSelector} from '../../hooks';

export default function ReviewForm(): JSX.Element {
const [formData, setFormData] = useState({
review: '',
rating: 0
});

const offerId = useAppSelector((state) => state.detailOffer)!.id;
const handleSubmit: React.FormEventHandler<HTMLFormElement> = (evt) => {
evt.preventDefault();
store.dispatch(
sendReview({
offerId,
rating: formData.rating,
comment: formData.review,
}),
);
};

const isValid =
formData.review.length >= minCommentLength &&
formData.review.length <= maxCommentLength &&
Expand All @@ -32,7 +47,7 @@ export default function ReviewForm(): JSX.Element {
}

return (
<form className="reviews__form form" action="#" method="post">
<form className="reviews__form form" onSubmit={handleSubmit}>
<label className="reviews__label form__label" htmlFor="review">Your review</label>
<div className="reviews__rating-form form__rating">
{renderRatingInput(5, 'perfect')}
Expand All @@ -46,7 +61,12 @@ export default function ReviewForm(): JSX.Element {
<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">{minCommentLength} characters</b>.
</p>
<button className="reviews__submit form__submit button" type="submit" disabled={!isValid}>Submit</button>
<button
className="reviews__submit form__submit button"
type="submit"
disabled={!isValid}
>Submit
</button>
</div>
</form>
);
Expand Down
15 changes: 7 additions & 8 deletions src/pages/login-screen/login-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ export function LoginScreen() : JSX.Element {
const submitHandle = (evt: FormEvent) => {
evt.preventDefault();
store.dispatch(login(loginInfo));
console.log(loginInfo)
}
};

return (
<div className="page page--gray page--login">
Expand Down Expand Up @@ -51,9 +50,9 @@ export function LoginScreen() : JSX.Element {
setLoginInfo({
...loginInfo,
email: event.target.value
})
}
required/>
})}
required
/>
</div>
<div className="login__input-wrapper form__input-wrapper">
<label className="visually-hidden">Password</label>
Expand All @@ -66,9 +65,9 @@ export function LoginScreen() : JSX.Element {
setLoginInfo({
...loginInfo,
password: event.target.value
})
}
required/>
})}
required
/>
</div>
<button
className="login__submit form__submit button"
Expand Down
62 changes: 42 additions & 20 deletions src/pages/main-screen/main-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import {JSX} from 'react';
import {JSX, useState} from 'react';
import {Helmet} from 'react-helmet-async';
import {OffersList} from '../../components/offers-list/offers-list.tsx';
import {Link} from 'react-router-dom';
import {AppRoute} from '../../const.ts';
import {useState} from 'react';
import {AppRoute, AuthorizationStatus} from '../../const.ts';
import {Map} from '../../components/map/map.tsx';
import {CitiesList} from '../../components/cities-list/cities-list.tsx';
import {useAppSelector} from '../../hooks';
import {Sorting} from '../../components/sorting/sorting.tsx';
import {SortOption} from '../../types/sort-option.ts';
import {store} from '../../store';
import {logout} from '../../store/api-actions.ts';


export function MainScreen(): JSX.Element {
Expand Down Expand Up @@ -39,6 +40,11 @@ export function MainScreen(): JSX.Element {
setSortingOption(option);
};

const isAuth = useAppSelector((state) => state.authorizationStatus) === AuthorizationStatus.Authorized;

const logoutHandle = () => {
store.dispatch(logout());
};

return (
<div className="page page--gray page--main">
Expand All @@ -53,23 +59,39 @@ export function MainScreen(): JSX.Element {
<img className="header__logo" src="img/logo.svg" alt="6 cities logo" width="81" height="41"/>
</a>
</div>
<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={AppRoute.Favorites}>
<div className="header__avatar-wrapper user__avatar-wrapper">
</div>
<span className="header__user-name user__name">[email protected]</span>
<span className="header__favorite-count">{favoritesCount}</span>
</Link>
</li>
<li className="header__nav-item">
<a className="header__nav-link" href="#">
<span className="header__signout">Sign out</span>
</a>
</li>
</ul>
</nav>
{isAuth ? (
<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={AppRoute.Favorites}>
<div className="header__avatar-wrapper user__avatar-wrapper">
</div>
<span className="header__user-name user__name">[email protected]</span>
<span className="header__favorite-count">{favoritesCount}</span>
</Link>
</li>
<li className="header__nav-item">
<a className="header__nav-link" onClick={logoutHandle}>
<span className="header__signout">Sign out</span>
</a>
</li>
</ul>
</nav>
) : (
<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={AppRoute.Login}
>
<div className="header__avatar-wrapper user__avatar-wrapper"></div>
<span className="header__login">Sign in</span>
</Link>
</li>
</ul>
</nav>
)}
</div>
</div>
</header>
Expand Down
5 changes: 3 additions & 2 deletions src/pages/offer-screen/offer-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {JSX, useEffect} from 'react';
import {Helmet} from 'react-helmet-async';
import {Link, Navigate, useParams} from 'react-router-dom';
import {AppRoute} from '../../const.ts';
import {AppRoute, AuthorizationStatus} from '../../const.ts';
import ReviewForm from '../../components/review-form/review-form.tsx';
import {Map} from '../../components/map/map.tsx';
import {ReviewList} from '../../components/review-list/review-list.tsx';
Expand All @@ -28,6 +28,7 @@ export function OfferScreen() : JSX.Element {
);
const reviews = useAppSelector((state) => state.reviews);
const favoriteCount = useAppSelector((state) => state.offers).filter((commonOffer) => commonOffer.isFavorite).length;
const isAuth = useAppSelector((state) => state.authorizationStatus) === AuthorizationStatus.Authorized;

if (offer === null){
return (<Loading />);
Expand Down Expand Up @@ -158,7 +159,7 @@ export function OfferScreen() : JSX.Element {
<section className="offer__reviews reviews">
<h2 className="reviews__title">Reviews &middot; <span className="reviews__amount">{reviews.length}</span></h2>
<ReviewList reviews={reviews} />
<ReviewForm />
{isAuth && <ReviewForm/>}
</section>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/servises/api.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import axios, {AxiosError, AxiosInstance, InternalAxiosRequestConfig} from 'axios';
import {getToken} from './token.ts';
import {store} from '../store';
import {setAuthorizationStatus} from '../store/action.ts';
import {setAuthorizationStatus, setDetailOffer} from '../store/action.ts';
import {AuthorizationStatus} from '../const.ts';

const baseURL = 'https://14.design.htmlacademy.pro/six-cities';
Expand Down Expand Up @@ -38,6 +38,9 @@ export const createAPI = () : AxiosInstance => {
setAuthorizationStatus(AuthorizationStatus.Unauthorized),
);
}
if (error.response && error.response.status === 404) {
store.dispatch(setDetailOffer(undefined));
}
throw error;
},
);
Expand Down
84 changes: 49 additions & 35 deletions src/store/api-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {Offer} from '../types/offer.ts';
import {apiRoute, AuthorizationStatus} from '../const.ts';
import {setOffers, setDetailOffer, setNearOffers, setReviews, setAuthorizationStatus} from './action.ts';
import {DetailOffer} from '../types/detail-offer.ts';
import {Review} from '../types/review.ts';
import {Review, ReviewInfo} from '../types/review.ts';
import {saveToken} from '../servises/token.ts';
import {AuthInfo, LoginInfo} from '../types/user.ts';
import {store} from './index.ts';

export const fetchOffers = createAsyncThunk<void, undefined, {
dispatch: AppDispatch;
Expand Down Expand Up @@ -57,40 +58,53 @@ export const fetchReviews = createAsyncThunk<void, Offer['id'], {
}
);

export const login = createAsyncThunk<void, LoginInfo,
{
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}
>('auth/login', async (loginInfo, { dispatch, extra: api }) => {
const response = await api.post<AuthInfo>(apiRoute.login, loginInfo);
if (response.status === 200 || response.status === 201) {
dispatch(setAuthorizationStatus(AuthorizationStatus.Authorized));
saveToken(response.data.token);
} else {
throw response;
export const sendReview = createAsyncThunk<void, ReviewInfo, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'data/fetchReviews', async (reviewInfo, {extra: api}) => {
const response = await api.post(`${apiRoute.reviews}/${reviewInfo.offerId}`, {
comment: reviewInfo.comment,
rating: Number(reviewInfo.rating)
});
if (response.status === 201) {
store.dispatch(fetchReviews(reviewInfo.offerId));
}
}
});
);

export const checkAuthorization = createAsyncThunk<void, undefined,
{
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}
>('auth/checkAuthorization', async (_arg, { dispatch, extra: api }) => {
await api.get(apiRoute.login);
dispatch(setAuthorizationStatus(AuthorizationStatus.Unauthorized));
});
export const login = createAsyncThunk<void, LoginInfo, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'auth/login', async (loginInfo, { dispatch, extra: api }) => {
const response = await api.post<AuthInfo>(apiRoute.login, loginInfo);
if (response.status === 200 || response.status === 201) {
dispatch(setAuthorizationStatus(AuthorizationStatus.Authorized));
saveToken(response.data.token);
} else {
throw response;
}
});

export const logut = createAsyncThunk<void, undefined,
{
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}
>('auth/logout', async (_arg, { dispatch, extra: api }) => {
await api.delete(apiRoute.logout);
dispatch(setAuthorizationStatus(AuthorizationStatus.Unauthorized));
});
export const checkAuthorization = createAsyncThunk<void, undefined, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'auth/checkAuthorization', async (_arg, { dispatch, extra: api }) => {
await api.get(apiRoute.login);
dispatch(setAuthorizationStatus(AuthorizationStatus.Unauthorized));
});

export const logout = createAsyncThunk<void, undefined, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'auth/logout', async (_arg, { dispatch, extra: api }) => {
await api.delete(apiRoute.logout);
dispatch(setAuthorizationStatus(AuthorizationStatus.Unauthorized));
});
6 changes: 6 additions & 0 deletions src/types/review.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,9 @@ export type Review = {
comment: string;
rating: number;
};

export type ReviewInfo = {
offerId: string;
comment: string;
rating: number;
};

0 comments on commit 659dd43

Please sign in to comment.