diff --git a/src/const.ts b/src/const.ts
index 6a410b7..1770d1b 100644
--- a/src/const.ts
+++ b/src/const.ts
@@ -126,4 +126,9 @@ export enum FavoriteStatus {
Add
}
+export enum LoadingStatus {
+ Loading = 'loading' ,
+ Succeed = 'succeed',
+ Failed = 'failed'
+}
diff --git a/src/pages/main-empty-screen/main-empty-screen.tsx b/src/pages/main-empty-screen/main-empty-screen.tsx
new file mode 100644
index 0000000..a116d5b
--- /dev/null
+++ b/src/pages/main-empty-screen/main-empty-screen.tsx
@@ -0,0 +1,66 @@
+import {JSX} from 'react';
+import MemoizedHeader from '../../components/header/header.tsx';
+import {Helmet} from 'react-helmet-async';
+
+export function MainEmptyScreen() : JSX.Element {
+ return (
+
diff --git a/src/pages/offer-screen/offer-screen.tsx b/src/pages/offer-screen/offer-screen.tsx
index 2fcab2a..e27df31 100644
--- a/src/pages/offer-screen/offer-screen.tsx
+++ b/src/pages/offer-screen/offer-screen.tsx
@@ -1,7 +1,7 @@
import {JSX, useEffect, useMemo} from 'react';
import {Helmet} from 'react-helmet-async';
import {Navigate, useParams} from 'react-router-dom';
-import {AuthorizationStatus} from '../../const.ts';
+import {AuthorizationStatus, LoadingStatus} from '../../const.ts';
import {Map} from '../../components/map/map.tsx';
import MemoizedReviewList from '../../components/review-list/review-list.tsx';
import {OffersList} from '../../components/offers-list/offers-list.tsx';
@@ -13,6 +13,7 @@ import {setDetailOffer} from '../../store/detail-offer-data/detail-offer-data.ts
import {getDetailOffer, getNearOffers, getReviews} from '../../store/detail-offer-data/selectors.ts';
import {getAuthoriztionStatus} from '../../store/user-data/selectors.ts';
import MemoizedReviewForm from '../../components/review-form/review-form.tsx';
+import {getLoadingStatus} from '../../store/app-data/selectors.ts';
export function OfferScreen() : JSX.Element {
const {id} = useParams();
@@ -29,15 +30,20 @@ export function OfferScreen() : JSX.Element {
const memoizedNearOffers = useMemo(() => nearOffers.slice(0, 3), [nearOffers]);
const reviews = useAppSelector(getReviews);
const isAuth = useAppSelector(getAuthoriztionStatus) === AuthorizationStatus.Authorized;
+ const loadingStatus = useAppSelector(getLoadingStatus);
- if (offer === null){
- return (
);
+ if (loadingStatus === LoadingStatus.Loading){
+ return
;
}
- if (offer === undefined) {
+ if (loadingStatus === LoadingStatus.Failed && !offer) {
return
;
}
+ if (!offer) {
+ return <> >;
+ }
+
return (
@@ -137,7 +143,7 @@ export function OfferScreen() : JSX.Element {
diff --git a/src/servises/api.ts b/src/servises/api.ts
index ae718db..01f31e5 100644
--- a/src/servises/api.ts
+++ b/src/servises/api.ts
@@ -3,7 +3,6 @@ import {getToken} from './token.ts';
import {store} from '../store';
import {AuthorizationStatus} from '../const.ts';
import {setAuthorizationStatus} from '../store/user-data/user-data.ts';
-import {setDetailOffer} from '../store/detail-offer-data/detail-offer-data.ts';
const baseURL = 'https://14.design.htmlacademy.pro/six-cities';
const requestTimeout = 5000;
@@ -39,9 +38,6 @@ export const createAPI = () : AxiosInstance => {
setAuthorizationStatus(AuthorizationStatus.Unauthorized),
);
}
- if (error.response && error.response.status === 404) {
- store.dispatch(setDetailOffer(undefined));
- }
throw error;
},
);
diff --git a/src/store/api-actions.ts b/src/store/api-actions.ts
index 746da9b..220fde4 100644
--- a/src/store/api-actions.ts
+++ b/src/store/api-actions.ts
@@ -2,16 +2,17 @@ import {createAsyncThunk} from '@reduxjs/toolkit';
import {AppDispatch, State} from '../types/state.ts';
import {AxiosInstance} from 'axios';
import {Offer} from '../types/offer.ts';
-import {ApiRoute, AuthorizationStatus} from '../const.ts';
+import {ApiRoute, AuthorizationStatus, LoadingStatus} from '../const.ts';
import {DetailOffer} from '../types/detail-offer.ts';
import {Review, ReviewInfo} from '../types/review.ts';
-import {saveToken, dropToken, getToken} from '../servises/token.ts';
+import {dropToken, getToken, saveToken} from '../servises/token.ts';
import {AuthInfo, LoginInfo} from '../types/user.ts';
import {store} from './index.ts';
import {FavoriteInfo} from '../types/favorite-info.ts';
import {setFavoritesCount, setFavoritesOffers, setOffers, updateOffers} from './offers-data/offers-data.ts';
import {setDetailOffer, setNearOffers, setReviews} from './detail-offer-data/detail-offer-data.ts';
import {saveUserEmail, setAuthorizationStatus} from './user-data/user-data.ts';
+import {setLoadingStatus} from './app-data/app-data.ts';
export const fetchOffers = createAsyncThunk
(
'data/fetchOffers',
async (_arg, {dispatch, extra: api}) => {
- const {data} = await api.get(ApiRoute.offers);
- dispatch(setOffers(data));
+ dispatch(setLoadingStatus(LoadingStatus.Loading));
+ try {
+ const { data } = await api.get(ApiRoute.offers);
+ dispatch(setOffers(data)); // обновляем данные
+ dispatch(setLoadingStatus(LoadingStatus.Succeed));
+ } catch (error) {
+ dispatch(setLoadingStatus(LoadingStatus.Failed));
+ throw error;
+ }
}
);
@@ -59,8 +67,15 @@ export const fetchDetailOffer = createAsyncThunk(
'data/fetchDetailOffer',
async (offerId, {dispatch, extra: api}) => {
- const {data} = await api.get(`${ApiRoute.offers}/${offerId}`);
- dispatch(setDetailOffer(data));
+ dispatch(setLoadingStatus(LoadingStatus.Loading));
+ try {
+ const {data} = await api.get(`${ApiRoute.offers}/${offerId}`);
+ dispatch(setDetailOffer(data));
+ dispatch(setLoadingStatus(LoadingStatus.Succeed));
+ } catch (error) {
+ dispatch(setLoadingStatus(LoadingStatus.Failed));
+ throw error;
+ }
}
);
diff --git a/src/store/app-data/app-data.ts b/src/store/app-data/app-data.ts
index 944e1f4..84e9f88 100644
--- a/src/store/app-data/app-data.ts
+++ b/src/store/app-data/app-data.ts
@@ -1,10 +1,11 @@
import {AppData} from '../../types/state.ts';
-import {Namespace, Paris} from '../../const.ts';
+import {LoadingStatus, Namespace, Paris} from '../../const.ts';
import {createSlice, PayloadAction} from '@reduxjs/toolkit';
import {City} from '../../types/city.ts';
const initialState: AppData = {
- city: Paris
+ city: Paris,
+ loadingStatus: null
};
export const appData = createSlice({
@@ -13,8 +14,11 @@ export const appData = createSlice({
reducers: {
changeActiveCity: (state, action: PayloadAction) => {
state.city = action.payload;
+ },
+ setLoadingStatus: (state, action: PayloadAction) => {
+ state.loadingStatus = action.payload;
}
}
});
-export const {changeActiveCity} = appData.actions;
+export const {changeActiveCity, setLoadingStatus} = appData.actions;
diff --git a/src/store/app-data/selectors.ts b/src/store/app-data/selectors.ts
index 4abfb58..555b384 100644
--- a/src/store/app-data/selectors.ts
+++ b/src/store/app-data/selectors.ts
@@ -1,5 +1,7 @@
import {State} from '../../types/state.ts';
-import {Namespace} from '../../const.ts';
+import {LoadingStatus, Namespace} from '../../const.ts';
import {City} from '../../types/city.ts';
export const getActiveCity = (state: State): City => state[Namespace.App].city;
+
+export const getLoadingStatus = (state: State): LoadingStatus | null => state[Namespace.App].loadingStatus;
diff --git a/src/store/detail-offer-data/detail-offer-data.ts b/src/store/detail-offer-data/detail-offer-data.ts
index 820f293..9c2609b 100644
--- a/src/store/detail-offer-data/detail-offer-data.ts
+++ b/src/store/detail-offer-data/detail-offer-data.ts
@@ -15,7 +15,7 @@ export const detailOfferData = createSlice({
name: Namespace.DetailOffer,
initialState,
reducers:{
- setDetailOffer: (state, action: PayloadAction) => {
+ setDetailOffer: (state, action: PayloadAction) => {
state.detailOffer = action.payload;
},
setNearOffers: (state, action: PayloadAction) => {
diff --git a/src/store/detail-offer-data/selectors.ts b/src/store/detail-offer-data/selectors.ts
index fe2c0e2..1f1cd4e 100644
--- a/src/store/detail-offer-data/selectors.ts
+++ b/src/store/detail-offer-data/selectors.ts
@@ -4,6 +4,6 @@ import {Namespace} from '../../const.ts';
import {Offer} from '../../types/offer.ts';
import {Review} from '../../types/review.ts';
-export const getDetailOffer = (state: State): DetailOffer | null | undefined=> state[Namespace.DetailOffer].detailOffer;
+export const getDetailOffer = (state: State): DetailOffer | null => state[Namespace.DetailOffer].detailOffer;
export const getNearOffers = (state: State): Offer[] => state[Namespace.DetailOffer].nearOffers;
export const getReviews = (state: State): Review[] => state[Namespace.DetailOffer].reviews;
diff --git a/src/types/state.ts b/src/types/state.ts
index e3673f0..e9d6825 100644
--- a/src/types/state.ts
+++ b/src/types/state.ts
@@ -3,7 +3,7 @@ import {City} from './city.ts';
import {DetailOffer} from './detail-offer.ts';
import {Offer} from './offer.ts';
import {Review} from './review.ts';
-import {AuthorizationStatus} from '../const.ts';
+import {AuthorizationStatus, LoadingStatus} from '../const.ts';
export type State = ReturnType;
@@ -11,10 +11,11 @@ export type AppDispatch = typeof store.dispatch;
export type AppData = {
city: City;
+ loadingStatus: LoadingStatus | null;
};
export type DetailOfferData = {
- detailOffer: DetailOffer | null | undefined;
+ detailOffer: DetailOffer | null;
nearOffers: Offer[];
reviews: Review[];
};