From 1cb285dc8618b67028771698460beb03da152328 Mon Sep 17 00:00:00 2001 From: iluvator Date: Sat, 9 Mar 2024 15:41:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A0=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BB=20=D1=81=D0=BE=D1=80=D1=82=D0=B8=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=D0=BA=D1=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/list-location.tsx | 5 +++-- src/components/location.tsx | 7 ++++--- src/components/map.tsx | 4 +++- src/components/places-option.tsx | 15 +++++++++++++++ src/components/places-options.tsx | 15 +++++++++++++++ src/const.ts | 4 +++- src/hooks/useMap.tsx | 4 +--- src/pages/main-page.tsx | 28 ++++++++++++++++++---------- src/store/action.ts | 3 ++- src/store/reducer.ts | 20 +++++++++++++++++++- src/utils/utils.ts | 14 +++++++++++++- 11 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 src/components/places-option.tsx create mode 100644 src/components/places-options.tsx diff --git a/src/components/list-location.tsx b/src/components/list-location.tsx index 170815a..bc06172 100644 --- a/src/components/list-location.tsx +++ b/src/components/list-location.tsx @@ -4,12 +4,13 @@ import { MouseEvent } from 'react'; type ListLocation = { listLocations: string[]; handleCurrentCityClick: (evt: MouseEvent) => void; + currentCity: string; } -export default function ListLocation({ listLocations, handleCurrentCityClick }: ListLocation) { +export default function ListLocation({ listLocations, handleCurrentCityClick, currentCity }: ListLocation) { return ( ); } diff --git a/src/components/location.tsx b/src/components/location.tsx index e3a9f8b..1691aae 100644 --- a/src/components/location.tsx +++ b/src/components/location.tsx @@ -1,11 +1,12 @@ type LocationProps = { city: string; + isActive: boolean; } -export default function Location({ city }: LocationProps) { +export default function Location({ city, isActive }: LocationProps) { return ( -
  • - +
  • + {city}
  • diff --git a/src/components/map.tsx b/src/components/map.tsx index 894f6b8..b111c7b 100644 --- a/src/components/map.tsx +++ b/src/components/map.tsx @@ -28,7 +28,7 @@ const currentCustomIcon = leaflet.icon({ export default function Map(props: MapProps): JSX.Element { const { city, offers, selectedOffer } = props; - console.log(city); + const mapRef = useRef(null); const map = useMap(mapRef, city); @@ -51,6 +51,8 @@ export default function Map(props: MapProps): JSX.Element { mapRef.current = null; }; } + + }, [map, offers, selectedOffer, city]); return ( diff --git a/src/components/places-option.tsx b/src/components/places-option.tsx new file mode 100644 index 0000000..0b88b2b --- /dev/null +++ b/src/components/places-option.tsx @@ -0,0 +1,15 @@ +import { SyntheticEvent } from 'react'; + +type PlacesOptionProps = { + place: string; + handelSortOfferClick: (sortType: string) => void; +} + +export default function PlacesOption({ place, handelSortOfferClick }: PlacesOptionProps) { + const onSortOfferClick = (evt: SyntheticEvent) => { + handelSortOfferClick(evt.target.textContent); + }; + return ( +
  • {place}
  • + ); +} diff --git a/src/components/places-options.tsx b/src/components/places-options.tsx new file mode 100644 index 0000000..6163c7e --- /dev/null +++ b/src/components/places-options.tsx @@ -0,0 +1,15 @@ +import PlacesOption from './places-option'; +import { placesOption } from '../const'; + +type PlacesOptionsProps = { + isOpen: boolean; + handelSortOfferClick: (sortType: string) => void; +} + +export default function PlacesOptions({ isOpen, handelSortOfferClick }: PlacesOptionsProps) { + return ( + + ); +} diff --git a/src/const.ts b/src/const.ts index ccc50f1..1776c12 100644 --- a/src/const.ts +++ b/src/const.ts @@ -34,6 +34,8 @@ 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 URL_MARKER_DEFAULT = '../markup/img/pin.svg'; const URL_MARKER_CURRENT = '../markup/img/pin-active.svg'; @@ -41,4 +43,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 }; +export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize, placesOption }; diff --git a/src/hooks/useMap.tsx b/src/hooks/useMap.tsx index 4251478..3260f7a 100644 --- a/src/hooks/useMap.tsx +++ b/src/hooks/useMap.tsx @@ -32,9 +32,7 @@ function useMap( setMap(instance); } - return () => { - isRenderedRef.current = true; - }; + isRenderedRef.current = true; }, [mapRef, city]); return map; diff --git a/src/pages/main-page.tsx b/src/pages/main-page.tsx index 8881fcd..51b1ee8 100644 --- a/src/pages/main-page.tsx +++ b/src/pages/main-page.tsx @@ -9,9 +9,9 @@ import { OfferPreviews } from '../types/offer-preview'; import { locations } from '../mocks/locations'; import ListLocation from '../components/list-location'; import { useAppDispatch, useAppSelector } from '../hooks'; -import { selectCity } from '../store/action'; +import { selectCity, sortOffer } from '../store/action'; import { offers } from '../mocks/offers'; - +import PlacesOptions from '../components/places-options'; export default function MainPage() { const baseOffers = offers; @@ -22,6 +22,10 @@ export default function MainPage() { null ); + const [isOpenSort, setIsOpenSort] = useState( + false + ); + const [selectedCity, setSelectedCity] = useState({ name: 'Paris', location: { @@ -31,6 +35,15 @@ export default function MainPage() { } }); + const handelSortOfferClick = (sortType: string) => { + dispatch(sortOffer(sortType)); + setIsOpenSort(!isOpenSort); + }; + + const handelOpenPlacesClick = () => { + setIsOpenSort(!isOpenSort); + }; + const handleListItemHover = (currentCard: OfferPreviews | null) => { setSelectedOffer(currentCard); }; @@ -55,7 +68,7 @@ export default function MainPage() {

    Cities

    - +
    @@ -67,18 +80,13 @@ export default function MainPage() { {selectOffers.length} place{selectOffers.length > 1 ? 's' : ''} to stay in Amsterdam
    Sort by - + Popular -
      -
    • Popular
    • -
    • Price: low to high
    • -
    • Price: high to low
    • -
    • Top rated first
    • -
    + : } diff --git a/src/store/action.ts b/src/store/action.ts index 4a58be8..3e2b35b 100644 --- a/src/store/action.ts +++ b/src/store/action.ts @@ -2,5 +2,6 @@ import { createAction } from '@reduxjs/toolkit'; import { Offer } from '../types/offer'; const selectCity = createAction('mainPage/selectCity'); +const sortOffer = createAction('mainPage/sortOffer'); -export { selectCity }; +export { selectCity, sortOffer }; diff --git a/src/store/reducer.ts b/src/store/reducer.ts index c634d1b..c8f495c 100644 --- a/src/store/reducer.ts +++ b/src/store/reducer.ts @@ -1,6 +1,8 @@ import { createReducer } from '@reduxjs/toolkit'; -import { selectCity } from './action'; +import { selectCity, sortOffer } from './action'; import { offers } from '../mocks/offers'; +import { placesOption } from '../const'; +import { sortPriceLow, sortPriceHigh, sortRating } from '../utils/utils'; const initialState = { city: 'Paris', @@ -12,6 +14,22 @@ const reducer = createReducer(initialState, (builder) => { .addCase(selectCity, (state, action) => { state.city = action.payload.city.name; 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; + } }); }); diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 275a9e8..d9bc3b9 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -19,4 +19,16 @@ function humanizeOrderData(date: string, format: string) { return date ? dayjs(date).format(format) : ''; } -export { getFavoritesByLocation, humanizeOrderData }; +function sortPriceLow(offerA: Offer, offerB: Offer,) { + return offerA.price - offerB.price; +} + +function sortPriceHigh(offerA: Offer, offerB: Offer,) { + return offerB.price - offerA.price; +} + +function sortRating(offerA: Offer, offerB: Offer,) { + return offerB.rating - offerA.rating; +} + +export { getFavoritesByLocation, humanizeOrderData, sortPriceLow, sortPriceHigh, sortRating };