From b2480cca6dc34a59f089272595d52001666a3639 Mon Sep 17 00:00:00 2001 From: iluvator Date: Wed, 13 Mar 2024 22:36:29 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=B8=D1=81=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B7=D0=B0=D0=BC=D0=B5=D1=87=D0=B0=D0=BD=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/list-location.tsx | 6 ++++-- src/components/places-options.tsx | 5 +++-- src/const.ts | 18 ++++++++++++++++-- src/hooks/sort.ts | 25 +++++++++++++++++++++++++ src/mocks/locations.ts | 1 - src/pages/main-page.tsx | 4 ++-- src/store/reducer.ts | 23 +++++------------------ src/types/list-location.ts | 8 ++++++++ 8 files changed, 63 insertions(+), 27 deletions(-) create mode 100644 src/hooks/sort.ts delete mode 100644 src/mocks/locations.ts create mode 100644 src/types/list-location.ts diff --git a/src/components/list-location.tsx b/src/components/list-location.tsx index 6af6b3a..02c85ec 100644 --- a/src/components/list-location.tsx +++ b/src/components/list-location.tsx @@ -1,16 +1,18 @@ import Location from './location'; import { SyntheticEvent } from 'react'; +import { listLocation } from '../types/list-location'; type ListLocation = { - listLocations: string[]; + listLocations: listLocation; handleCurrentCityClick: (evt: SyntheticEvent) => void; currentCity: string; } export default function ListLocation({ listLocations, handleCurrentCityClick, currentCity }: ListLocation) { + const listValuesLocations = Object.values(listLocations); return ( ); } diff --git a/src/components/places-options.tsx b/src/components/places-options.tsx index 6163c7e..771a029 100644 --- a/src/components/places-options.tsx +++ b/src/components/places-options.tsx @@ -1,5 +1,5 @@ import PlacesOption from './places-option'; -import { placesOption } from '../const'; +import { ListSort } from '../const'; type PlacesOptionsProps = { isOpen: boolean; @@ -7,9 +7,10 @@ type PlacesOptionsProps = { } export default function PlacesOptions({ isOpen, handelSortOfferClick }: PlacesOptionsProps) { + const listValuesSort = Object.values(ListSort); return ( ); } diff --git a/src/const.ts b/src/const.ts index 1776c12..ae11485 100644 --- a/src/const.ts +++ b/src/const.ts @@ -34,7 +34,21 @@ const OptionListCard = { CITIES_CARD: 'cities__places-list places__list tabs__content', }; -const placesOption = ['Popular', 'Price: low to high', 'Price: high to low', 'Top rated first',]; +const ListSort = { + SORT_POPULAR: 'Popular', + SORT_PRICE_HIGH: 'Price: low to high', + SORT_PRICE_LOW: 'Price: high to low', + SORT_RATED: 'Top rated first', +}; + +const ListLocation = { + PARIS: 'Paris', + COLOGNE: 'Cologne', + BRUSSELS: 'Brussels', + AMSTERDAM: 'Amsterdam', + HAMBURG: 'Hamburg', + DUSSELDORF: 'Dusseldorf', +}; const URL_MARKER_DEFAULT = '../markup/img/pin.svg'; @@ -43,4 +57,4 @@ const URL_MARKER_CURRENT = '../markup/img/pin-active.svg'; const CountStar: number = 5; -export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize, placesOption }; +export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize, ListSort, ListLocation as LocationCity }; diff --git a/src/hooks/sort.ts b/src/hooks/sort.ts new file mode 100644 index 0000000..aa73d56 --- /dev/null +++ b/src/hooks/sort.ts @@ -0,0 +1,25 @@ +import { Offer } from '../types/offer'; +import { ListSort } from '../const'; +import { sortPriceLow, sortPriceHigh, sortRating } from '../utils/utils'; +import { LocationCity } from '../const'; + +export function sortingOffers(action: string, state: Offer[], offers: Offer[]): Offer[] { + let sortOffers: Offer[] = []; + switch (action) { + case ListSort.SORT_POPULAR: + sortOffers = [...offers].filter((offer) => offer.city.name === LocationCity.PARIS); + break; + case ListSort.SORT_PRICE_HIGH: + sortOffers = state.sort(sortPriceHigh); + break; + case ListSort.SORT_PRICE_LOW: + sortOffers = state.sort(sortPriceLow); + break; + case ListSort.SORT_RATED: + sortOffers = state.sort(sortRating); + break; + } + + return sortOffers; +} + diff --git a/src/mocks/locations.ts b/src/mocks/locations.ts deleted file mode 100644 index a6fd1f8..0000000 --- a/src/mocks/locations.ts +++ /dev/null @@ -1 +0,0 @@ -export const locations = ['Paris', 'Cologne', 'Brussels', 'Amsterdam', 'Hamburg', 'Dusseldorf',]; diff --git a/src/pages/main-page.tsx b/src/pages/main-page.tsx index 484b2f1..9892e49 100644 --- a/src/pages/main-page.tsx +++ b/src/pages/main-page.tsx @@ -6,7 +6,7 @@ import { SyntheticEvent, useState } from 'react'; import MainEmpty from '../components/main-empty'; import { OptionListCard } from '../const'; import { OfferPreviews } from '../types/offer-preview'; -import { locations } from '../mocks/locations'; +import { LocationCity } from '../const'; import ListLocation from '../components/list-location'; import { useAppDispatch, useAppSelector } from '../hooks'; import { selectCity, sortOffer } from '../store/action'; @@ -74,7 +74,7 @@ export default function MainPage() {

Cities

- +
diff --git a/src/store/reducer.ts b/src/store/reducer.ts index 594c2fb..095702b 100644 --- a/src/store/reducer.ts +++ b/src/store/reducer.ts @@ -1,12 +1,12 @@ import { createReducer } from '@reduxjs/toolkit'; import { selectCity, sortOffer } from './action'; import { offers } from '../mocks/offers'; -import { placesOption } from '../const'; -import { sortPriceLow, sortPriceHigh, sortRating } from '../utils/utils'; +import { sortingOffers } from '../hooks/sort'; +import { LocationCity } from '../const'; const initialState = { - city: 'Paris', - offers: [...offers].filter((offer) => offer.city.name === 'Paris'), + city: LocationCity.PARIS, + offers: [...offers].filter((offer) => offer.city.name === LocationCity.PARIS), }; const reducer = createReducer(initialState, (builder) => { @@ -16,20 +16,7 @@ const reducer = createReducer(initialState, (builder) => { state.offers = [...offers].filter((offer) => offer.city.name === state.city); }) .addCase(sortOffer, (state, action) => { - switch (action.payload) { - case placesOption[0]: - state.offers = [...offers].filter((offer) => offer.city.name === state.city); - break; - case placesOption[1]: - state.offers = state.offers.sort(sortPriceHigh); - break; - case placesOption[2]: - state.offers = state.offers.sort(sortPriceLow); - break; - case placesOption[3]: - state.offers = state.offers.sort(sortRating); - break; - } + state.offers = sortingOffers(action.payload, state.offers, offers); }); }); diff --git a/src/types/list-location.ts b/src/types/list-location.ts new file mode 100644 index 0000000..4a27e86 --- /dev/null +++ b/src/types/list-location.ts @@ -0,0 +1,8 @@ +export type listLocation = { + PARIS: string; + COLOGNE: string; + BRUSSELS: string; + AMSTERDAM: string; + HAMBURG: string; + DUSSELDORF: string; +}; From 7047a59e0526cd4dee29a9f6bb3e5dde9ace675a Mon Sep 17 00:00:00 2001 From: iluvator Date: Sat, 16 Mar 2024 17:27:33 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA?= =?UTF-8?q?=D1=83=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20=D1=81=20=D1=81?= =?UTF-8?q?=D0=B5=D1=80=D0=B2=D0=B5=D1=80=D0=B0=20.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/app.tsx | 9 ++++ src/components/card.tsx | 16 +++++- src/components/list-cards.tsx | 3 +- src/components/loader/loader-style.css | 31 +++++++++++ src/components/loader/loader.tsx | 5 ++ src/components/map.tsx | 5 +- src/const.ts | 9 +++- src/hooks/sort.ts | 6 +-- src/index.tsx | 6 ++- src/pages/main-page.tsx | 4 +- src/pages/offer-page.tsx | 46 ++++++++--------- src/service/api.ts | 13 +++++ src/store/action.ts | 18 ++++++- src/store/api-action.ts | 71 ++++++++++++++++++++++++++ src/store/index.ts | 13 ++++- src/store/reducer.ts | 30 +++++++++-- src/utils/utils.ts | 7 +-- 17 files changed, 245 insertions(+), 47 deletions(-) create mode 100644 src/components/loader/loader-style.css create mode 100644 src/components/loader/loader.tsx create mode 100644 src/service/api.ts create mode 100644 src/store/api-action.ts diff --git a/src/components/app.tsx b/src/components/app.tsx index 3ee6b5a..1b8b677 100644 --- a/src/components/app.tsx +++ b/src/components/app.tsx @@ -6,8 +6,17 @@ import { Route, Routes } from 'react-router-dom'; import { AppRoute, authorizationStatus } from '../const'; import NotFoundPage from '../pages/not-found-page/not-found-page'; import ProtectedRoute from './protected-route'; +import { useAppSelector } from '../hooks'; +import Loader from './loader/loader'; export default function App() { + + const isOffersDataLoading = useAppSelector((state) => state.isOfferDataLoadingStatus); + + if (isOffersDataLoading) { + return ; + } + return ( diff --git a/src/components/card.tsx b/src/components/card.tsx index 0d52e66..435adaa 100644 --- a/src/components/card.tsx +++ b/src/components/card.tsx @@ -2,6 +2,11 @@ import { Link } from 'react-router-dom'; import { OfferPreviews } from '../types/offer-preview'; import Rating from './rating'; import { AppRoute } from '../const'; +import { fetchCommentsAction, fetchOfferAction } from '../store/api-action'; +import { chooseId } from '../store/action'; +import { useAppDispatch } from '../hooks'; +import { store } from '../store'; + type TCardProps = { offer: OfferPreviews; optionCard: { @@ -14,6 +19,13 @@ type TCardProps = { export default function Card({ offer, optionCard, handelPointCardMouseOver }: TCardProps) { const { width, height, classCard } = optionCard; + const dispatch = useAppDispatch(); + + const onTransmissionDataClick = () => { + dispatch(chooseId(offer.id)); + store.dispatch(fetchCommentsAction()); + store.dispatch(fetchOfferAction()); + }; const onPointCardMouseOver = () => { handelPointCardMouseOver(offer); @@ -31,7 +43,7 @@ export default function Card({ offer, optionCard, handelPointCardMouseOver }: TC
}
- + Place image
@@ -50,7 +62,7 @@ export default function Card({ offer, optionCard, handelPointCardMouseOver }: TC

- {offer.title} + {offer.title}

{offer.type}

diff --git a/src/components/list-cards.tsx b/src/components/list-cards.tsx index 11bd59e..0a5238f 100644 --- a/src/components/list-cards.tsx +++ b/src/components/list-cards.tsx @@ -1,10 +1,9 @@ import { OptionCard } from '../const'; -import { Offer } from '../types/offer'; import Card from './card'; import { OfferPreviews } from '../types/offer-preview'; type ListOfferNearbyProps = { - offers: Offer[]; + offers: OfferPreviews[]; onListItemHover: (currentCard: OfferPreviews | null) => void; extraClass: string; } diff --git a/src/components/loader/loader-style.css b/src/components/loader/loader-style.css new file mode 100644 index 0000000..4bdf21b --- /dev/null +++ b/src/components/loader/loader-style.css @@ -0,0 +1,31 @@ +.loader { + position: relative; + width: 64px; + height: 64px; + background-color: rgba(0, 0, 0, 0.5); + transform: rotate(45deg); + overflow: hidden; +} +.loader:after{ + content: ''; + position: absolute; + inset: 8px; + margin: auto; + background: #222b32; +} +.loader:before{ + content: ''; + position: absolute; + inset: -15px; + margin: auto; + background: #de3500; + animation: diamondLoader 2s linear infinite; +} +@keyframes diamondLoader { + 0% ,10% { + transform: translate(-64px , -64px) rotate(-45deg) + } + 90% , 100% { + transform: translate(0px , 0px) rotate(-45deg) + } +} diff --git a/src/components/loader/loader.tsx b/src/components/loader/loader.tsx new file mode 100644 index 0000000..dc039d0 --- /dev/null +++ b/src/components/loader/loader.tsx @@ -0,0 +1,5 @@ +import './loader-style.css'; + +export default function Loader() { + return ; +} diff --git a/src/components/map.tsx b/src/components/map.tsx index b111c7b..66c27dd 100644 --- a/src/components/map.tsx +++ b/src/components/map.tsx @@ -1,6 +1,5 @@ import leaflet from 'leaflet'; import 'leaflet/dist/leaflet.css'; -import { Offer } from '../types/offer'; import { useEffect, useRef } from 'react'; import { URL_MARKER_DEFAULT, URL_MARKER_CURRENT } from '../const'; import { City } from '../types/city'; @@ -10,7 +9,7 @@ import { MapSize } from '../const'; type MapProps = { city: City; - offers: Offer[]; + offers: OfferPreviews[]; selectedOffer: OfferPreviews | null; }; @@ -40,7 +39,7 @@ export default function Map(props: MapProps): JSX.Element { lat: offer.location.latitude, lng: offer.location.longitude }, { - icon: (selectedOffer !== null && offer.title === selectedOffer.title) + icon: (selectedOffer !== null && offer.id === selectedOffer.id) ? currentCustomIcon : defaultCustomIcon, }) diff --git a/src/const.ts b/src/const.ts index ae11485..9fdec05 100644 --- a/src/const.ts +++ b/src/const.ts @@ -50,6 +50,13 @@ const ListLocation = { DUSSELDORF: 'Dusseldorf', }; +const APIRoute = { + OFFERS: '/offers', + FAVORITE: '/favorite', + COMMENTS: '/comments', + USER: '/login', +}; + const URL_MARKER_DEFAULT = '../markup/img/pin.svg'; const URL_MARKER_CURRENT = '../markup/img/pin-active.svg'; @@ -57,4 +64,4 @@ const URL_MARKER_CURRENT = '../markup/img/pin-active.svg'; const CountStar: number = 5; -export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize, ListSort, ListLocation as LocationCity }; +export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize, ListSort, ListLocation as LocationCity, APIRoute }; diff --git a/src/hooks/sort.ts b/src/hooks/sort.ts index aa73d56..92b2508 100644 --- a/src/hooks/sort.ts +++ b/src/hooks/sort.ts @@ -1,10 +1,10 @@ -import { Offer } from '../types/offer'; +import { OfferPreviews } from '../types/offer-preview'; import { ListSort } from '../const'; import { sortPriceLow, sortPriceHigh, sortRating } from '../utils/utils'; import { LocationCity } from '../const'; -export function sortingOffers(action: string, state: Offer[], offers: Offer[]): Offer[] { - let sortOffers: Offer[] = []; +export function sortingOffers(action: string, state: OfferPreviews[], offers: OfferPreviews[]): OfferPreviews[] { + let sortOffers: OfferPreviews[] = []; switch (action) { case ListSort.SORT_POPULAR: sortOffers = [...offers].filter((offer) => offer.city.name === LocationCity.PARIS); diff --git a/src/index.tsx b/src/index.tsx index 7d23b82..58a8ef1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -3,9 +3,11 @@ import ReactDOM from 'react-dom/client'; import App from './components/app'; import { BrowserRouter } from 'react-router-dom'; import { HelmetProvider } from 'react-helmet-async'; -import { offers } from './mocks/offers'; import { Provider } from 'react-redux'; import { store } from './store'; +import { fetchOffersAction } from './store/api-action'; + +store.dispatch(fetchOffersAction()); const root = ReactDOM.createRoot( document.getElementById('root') as HTMLElement @@ -16,7 +18,7 @@ root.render( - + diff --git a/src/pages/main-page.tsx b/src/pages/main-page.tsx index 9892e49..64190b2 100644 --- a/src/pages/main-page.tsx +++ b/src/pages/main-page.tsx @@ -10,11 +10,9 @@ import { LocationCity } from '../const'; import ListLocation from '../components/list-location'; import { useAppDispatch, useAppSelector } from '../hooks'; import { selectCity, sortOffer } from '../store/action'; -import { offers } from '../mocks/offers'; import PlacesOptions from '../components/places-options'; export default function MainPage() { - const baseOffers = offers; const selectOffers = useAppSelector((state) => state.offers); const currentCity = useAppSelector((state) => state.city); const dispatch = useAppDispatch(); @@ -54,7 +52,7 @@ export default function MainPage() { const handleCurrentCityClick = (evt: SyntheticEvent) => { evt.preventDefault(); - const currentOffer = baseOffers.find((offer) => offer.city.name === evt.currentTarget.textContent); + const currentOffer = selectOffers.find((offer) => offer.city.name === evt.currentTarget.textContent); if (currentOffer !== undefined) { diff --git a/src/pages/offer-page.tsx b/src/pages/offer-page.tsx index 8b5185e..1ac2abe 100644 --- a/src/pages/offer-page.tsx +++ b/src/pages/offer-page.tsx @@ -4,8 +4,6 @@ import Rating from '../components/rating'; import { Helmet } from 'react-helmet-async'; import CommentsTemplate from '../components/comments-template'; import { CountStar } from '../const'; -import { useParams } from 'react-router-dom'; -import { Comments } from '../mocks/comments'; import ReviewsComments from '../components/reviews-comments'; import Map from '../components/map'; import { useState } from 'react'; @@ -15,8 +13,9 @@ import { OfferPreviews } from '../types/offer-preview'; import { useAppSelector } from '../hooks'; export default function OfferPage() { - const offers = useAppSelector((state) => state.offers); - + const offer = useAppSelector((state) => state.currentOffer); + const offersNearby = useAppSelector((state) => state.offers); + const comments = useAppSelector((state) => state.comments); const [selectedOffer, setSelectedOffer] = useState( null ); @@ -27,10 +26,11 @@ export default function OfferPage() { } }; - const { offerId } = useParams(); - const dataOffer = offers.find((offer) => offer.id === offerId); + // const { offerId } = useParams(); + // const offer = offers.find((offer) => offer.id === offerId); + // console.log(offer); - if (dataOffer === undefined) { + if (offer === undefined) { return; } @@ -42,7 +42,7 @@ export default function OfferPage() {
- {dataOffer.images.map((image: string) => ( + {offer.images.map((image: string) => (
Photo studio
@@ -52,14 +52,14 @@ export default function OfferPage() {
- {dataOffer.isPremium && + {offer.isPremium &&
Premium
}

- {dataOffer.title} + {offer.title}

- +
  • - {dataOffer.type && dataOffer.type} + {offer.type && offer.type}
  • - {dataOffer.bedrooms && `${dataOffer.bedrooms} Bedrooms`} + {offer.bedrooms && `${offer.bedrooms} Bedrooms`}
  • - {dataOffer.maxAdults && `Max ${dataOffer.maxAdults} adults`} + {offer.maxAdults && `Max ${offer.maxAdults} adults`}
- €{dataOffer.price} + €{offer.price}  night

What's inside

    - {dataOffer.goods.map((good) => )} + {offer.goods.map((good) => )}

Meet the host

- Host avatar + Host avatar
- {dataOffer.host.name} + {offer.host.name} - {dataOffer.host.isPro && + {offer.host.isPro && Pro } @@ -114,20 +114,20 @@ export default function OfferPage() {
-

Reviews · 1

- +

Reviews · {comments.length}

+
- +

Other places in the neighbourhood

- +
diff --git a/src/service/api.ts b/src/service/api.ts new file mode 100644 index 0000000..811032c --- /dev/null +++ b/src/service/api.ts @@ -0,0 +1,13 @@ +import axios, { AxiosInstance } from 'axios'; + +const BASE_URL = 'https://15.design.htmlacademy.pro/six-cities'; +const REQUEST_TIMEOUT = 5000; + +export const createAPI = (): AxiosInstance => { + const api = axios.create({ + baseURL: BASE_URL, + timeout: REQUEST_TIMEOUT, + }); + + return api; +}; diff --git a/src/store/action.ts b/src/store/action.ts index 66ea6c7..70cc84a 100644 --- a/src/store/action.ts +++ b/src/store/action.ts @@ -1,6 +1,22 @@ import { createAction } from '@reduxjs/toolkit'; +import { Offer } from '../types/offer'; +import { OfferPreviews } from '../types/offer-preview'; +import { Comment } from '../types/comment'; const selectCity = createAction('mainPage/selectCity'); + const sortOffer = createAction('mainPage/sortOffer'); -export { selectCity, sortOffer }; +const loadOffer = createAction('data/loadOffers'); + +const loadComments = createAction('data/loadComments'); + +const loadFavorite = createAction('data/loadFavorite'); + +const chooseOffer = createAction('mainPage/chooseOffer'); + +const chooseId = createAction('mainPage/chooseId'); + +const setOfferDataLoadingStatus = createAction('data/setOfferDataLoadingStatus'); + +export { selectCity, sortOffer, loadOffer, setOfferDataLoadingStatus, loadComments, loadFavorite, chooseOffer, chooseId }; diff --git a/src/store/api-action.ts b/src/store/api-action.ts new file mode 100644 index 0000000..8fb695f --- /dev/null +++ b/src/store/api-action.ts @@ -0,0 +1,71 @@ +import { createAsyncThunk } from '@reduxjs/toolkit'; +import { AppDispatch, State } from '../types/state'; +import { AxiosInstance } from 'axios'; +import { Offer } from '../types/offer'; +import { APIRoute } from '../const'; +import { Comment } from '../types/comment'; +import { loadOffer, setOfferDataLoadingStatus, loadComments, loadFavorite, chooseOffer } from './action'; + +export const fetchOffersAction = createAsyncThunk( + 'data/fetchOffers', + async (_arg, { dispatch, extra: api }) => { + dispatch(setOfferDataLoadingStatus(true)); + const { data } = await api.get(APIRoute.OFFERS); + dispatch(setOfferDataLoadingStatus(false)); + dispatch(loadOffer(data)); + }, +); + +export const fetchCommentsAction = createAsyncThunk( + 'data/loadComments', + async (_arg, { dispatch, getState, extra: api }) => { + const state = getState(); + dispatch(setOfferDataLoadingStatus(true)); + const { data } = await api.get(`${APIRoute.COMMENTS}/${state.idOffer}`); + dispatch(setOfferDataLoadingStatus(false)); + console.log(data); + dispatch(loadComments(data)); + }, +); + +export const fetchOfferAction = createAsyncThunk( + 'mainPage/chooseOffer', + async (_arg, { dispatch, getState, extra: api }) => { + const state = getState(); + dispatch(setOfferDataLoadingStatus(true)); + const { data } = await api.get(`${APIRoute.OFFERS}/${state.idOffer}`); + dispatch(setOfferDataLoadingStatus(false)); + console.log(data); + dispatch(chooseOffer(data)); + }, +); + +// export const fetchFavoriteAction = createAsyncThunk( +// 'data/fetchOffers', +// async (_arg, { dispatch, extra: api }) => { +// dispatch(setOfferDataLoadingStatus(true)); +// const { data } = await api.get(APIRoute.OFFERS); +// const { comments } = await api.get(APIRoute.COMMENTS); +// const { favorite } = await api.get(APIRoute.FAVORITE); +// const { user } = await api.get(APIRoute.USER); +// dispatch(setOfferDataLoadingStatus(false)); +// dispatch(loadOffer(data)); +// }, +// ); + diff --git a/src/store/index.ts b/src/store/index.ts index b6e9107..979ce10 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -1,6 +1,17 @@ import { configureStore } from '@reduxjs/toolkit'; import { reducer } from './reducer'; +import { createAPI } from '../service/api'; -const store = configureStore({ reducer }); +const api = createAPI(); + +const store = configureStore({ + reducer, + middleware: (getDefaultMiddleware) => + getDefaultMiddleware({ + thunk: { + extraArgument: api, + }, + }) +}); export { store }; diff --git a/src/store/reducer.ts b/src/store/reducer.ts index 095702b..b526d90 100644 --- a/src/store/reducer.ts +++ b/src/store/reducer.ts @@ -1,22 +1,46 @@ import { createReducer } from '@reduxjs/toolkit'; -import { selectCity, sortOffer } from './action'; +import { selectCity, sortOffer, loadOffer, setOfferDataLoadingStatus, loadComments, chooseOffer, chooseId } from './action'; import { offers } from '../mocks/offers'; import { sortingOffers } from '../hooks/sort'; import { LocationCity } from '../const'; +import { Offer } from '../types/offer'; +import { OfferPreviews } from '../types/offer-preview'; +import { Comment } from '../types/comment'; const initialState = { city: LocationCity.PARIS, - offers: [...offers].filter((offer) => offer.city.name === LocationCity.PARIS), + offers: [], + initialOffers: [], + isOfferDataLoadingStatus: false, + comments: [], + currentOffer: null, + idOffer: null, }; const reducer = createReducer(initialState, (builder) => { builder .addCase(selectCity, (state, action) => { state.city = action.payload; - state.offers = [...offers].filter((offer) => offer.city.name === state.city); + state.offers = state.initialOffers.filter((offer) => offer.city.name === state.city); }) .addCase(sortOffer, (state, action) => { state.offers = sortingOffers(action.payload, state.offers, offers); + }) + .addCase(loadOffer, (state, action) => { + state.initialOffers = action.payload; + state.offers = state.initialOffers.filter((offer) => offer.city.name === state.city); + }) + .addCase(setOfferDataLoadingStatus, (state, action) => { + state.isOfferDataLoadingStatus = action.payload; + }) + .addCase(chooseId, (state, action) => { + state.idOffer = action.payload; + }) + .addCase(loadComments, (state, action) => { + state.comments = action.payload; + }) + .addCase(chooseOffer, (state, action) => { + state.currentOffer = action.payload; }); }); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index d9bc3b9..d213365 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -1,4 +1,5 @@ import { Offer } from '../types/offer'; +import { OfferPreviews } from '../types/offer-preview'; import dayjs from 'dayjs'; function getFavoritesByLocation(favorites: Offer[]) { @@ -19,15 +20,15 @@ function humanizeOrderData(date: string, format: string) { return date ? dayjs(date).format(format) : ''; } -function sortPriceLow(offerA: Offer, offerB: Offer,) { +function sortPriceLow(offerA: OfferPreviews, offerB: OfferPreviews,) { return offerA.price - offerB.price; } -function sortPriceHigh(offerA: Offer, offerB: Offer,) { +function sortPriceHigh(offerA: OfferPreviews, offerB: OfferPreviews,) { return offerB.price - offerA.price; } -function sortRating(offerA: Offer, offerB: Offer,) { +function sortRating(offerA: OfferPreviews, offerB: OfferPreviews,) { return offerB.rating - offerA.rating; }