Skip to content

Commit

Permalink
module6-task2
Browse files Browse the repository at this point in the history
  • Loading branch information
Mayanzev committed Apr 23, 2024
1 parent 47cf6b9 commit 4dec8ce
Show file tree
Hide file tree
Showing 12 changed files with 142 additions and 49 deletions.
28 changes: 28 additions & 0 deletions src/components/cards-sorting-options/cards-sorting-options.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react";

Check failure on line 1 in src/components/cards-sorting-options/cards-sorting-options.tsx

View workflow job for this annotation

GitHub Actions / Check

Strings must use singlequote
import { useAppDispatch, useAppSelector } from "../../hooks";

Check failure on line 2 in src/components/cards-sorting-options/cards-sorting-options.tsx

View workflow job for this annotation

GitHub Actions / Check

Strings must use singlequote
import { filters } from "../../const";

Check failure on line 3 in src/components/cards-sorting-options/cards-sorting-options.tsx

View workflow job for this annotation

GitHub Actions / Check

Strings must use singlequote
import { changeSortOptions } from "../../store/action";

Check failure on line 4 in src/components/cards-sorting-options/cards-sorting-options.tsx

View workflow job for this annotation

GitHub Actions / Check

Strings must use singlequote

function CardsSortingOptions(): JSX.Element {
const chosenSortType = useAppSelector((state) => state.sortType);
const dispatch = useAppDispatch();
const [isSortOpened, setIsSortOpened] = React.useState(false);
return (
<form className="places__sorting" action="#" method="get">
<span className="places__sorting-caption">Sort by</span>
<span className="places__sorting-type" tabIndex={0} onClick={() => setIsSortOpened(!isSortOpened)}>
{chosenSortType}
<svg className="places__sorting-arrow" width="7" height="4">
<use xlinkHref="#icon-arrow-select"></use>
</svg>
</span>
<ul className={`places__options places__options--custom ${(isSortOpened) ? 'places__options--opened' : ''}`}>
<li className={`places__option ${(chosenSortType === filters.POPULAR) ? 'places__option--active' : ''}`} tabIndex={0} onClick={() => dispatch(changeSortOptions(filters.POPULAR))}>Popular</li>
<li className={`places__option ${(chosenSortType === filters.LOW_TO_HIGH) ? 'places__option--active' : ''}`} tabIndex={0} onClick={() => dispatch(changeSortOptions(filters.LOW_TO_HIGH))}>Price: low to high</li>
<li className={`places__option ${(chosenSortType === filters.HIGH_TO_LOW) ? 'places__option--active' : ''}`} tabIndex={0} onClick={() => dispatch(changeSortOptions(filters.HIGH_TO_LOW))}>Price: high to low</li>
<li className={`places__option ${(chosenSortType === filters.TOP_RATED) ? 'places__option--active' : ''}`} tabIndex={0} onClick={() => dispatch(changeSortOptions(filters.TOP_RATED))}>Top rated first</li>
</ul>
</form>
);
}
export default CardsSortingOptions;
34 changes: 27 additions & 7 deletions src/components/map/map.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,32 @@
import React, { useEffect } from 'react';
import { Marker, layerGroup } from 'leaflet';
import { Icon, Marker, layerGroup } from 'leaflet';
import useMap from '../../hooks/use-map';
import { City } from '../../types/city';
import { Point } from '../../types/point';
import 'leaflet/dist/leaflet.css';
import { useAppSelector } from '../../hooks';
import { URL_MARKER_CURRENT, URL_MARKER_STANDART } from '../../const';

type MapProps = {
city: City;
points: Point[];
selectedPoint?: Point;
}

const currentIcon = new Icon({
iconUrl: URL_MARKER_CURRENT,
iconSize: [32, 32],
iconAnchor: [20, 40]
});

const standartIcon = new Icon({
iconUrl: URL_MARKER_STANDART,
iconSize: [32, 32],
iconAnchor: [20, 40]
});

function Map(props: MapProps): JSX.Element {
const {city, points, selectedPoint} = props;
const city = useAppSelector((state) => state.city);
const highlightedMarker = useAppSelector((state) => state.highlightedMarker);

const {points} = props;
const mapRef = React.useRef(null);
const map = useMap(mapRef, city);

Expand All @@ -25,15 +38,22 @@ function Map(props: MapProps): JSX.Element {
lat: point.lat,
lng: point.lng
});
let icon;
if (point === highlightedMarker) {
icon = currentIcon;
} else {
icon = standartIcon;
}
marker
.setIcon(icon)
.addTo(markerLayer);
});

map.setView([city.lat, city.lng], 11);
return () => {
map.removeLayer(markerLayer);
};
}
}, [map, points, selectedPoint]);
}, [map, points, highlightedMarker, city]);

return <div style={{height: '100%'}} ref={mapRef}></div>;
}
Expand Down
8 changes: 7 additions & 1 deletion src/components/offer-card/offer-card.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { useAppDispatch } from '../../hooks';
import { changeHighlightedMarker } from '../../store/action';
import { Offer } from '../../types/offer';
import { Link } from 'react-router-dom';

Expand All @@ -7,8 +9,12 @@ type OfferProps = {
}

function OfferCard({offer, cardType}: OfferProps): JSX.Element {
const dispatch = useAppDispatch();
return (
<article className={cardType}>
<article className={cardType}
onMouseEnter={() => dispatch(changeHighlightedMarker(offer.point))}
onMouseLeave={() => dispatch(changeHighlightedMarker(undefined))}
>
{offer.isPremium ? (
<div className="place-card__mark">
<span>Premium</span>
Expand Down
6 changes: 4 additions & 2 deletions src/components/offer-list/offer-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { listToCard, typeOfCardList } from '../../const';
import { getSortedOffers, listToCard, typeOfCardList } from '../../const';
import { useAppSelector } from '../../hooks';
import { Offer } from '../../types/offer';
import OfferCard from '../offer-card/offer-card';

Expand All @@ -8,10 +9,11 @@ type OfferListProps = {
};

function OfferList({offers, listType}: OfferListProps): JSX.Element {
const chosenSortType = useAppSelector((state) => state.sortType);
const type = listToCard.get(listType);
return (
<div className={(listType)}>
{offers.map((offer) => (
{getSortedOffers(offers, chosenSortType)?.map((offer) => (
<OfferCard key={offer.id} offer={offer} cardType={(type !== undefined) ? type : 'cities__card place-card'}/>
))}
</div>
Expand Down
34 changes: 31 additions & 3 deletions src/const.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
export const Settings = {
placesCount: 55,
} as const;
import { Offer } from "./types/offer";

Check failure on line 1 in src/const.ts

View workflow job for this annotation

GitHub Actions / Check

Strings must use singlequote

export enum AppRoute {
Main = '/',
Expand Down Expand Up @@ -28,3 +26,33 @@ export const listToCard = new Map(
[typeOfCardList.standart, 'cities__card place-card']
]
);

export const filters = {
POPULAR: 'Popular',
LOW_TO_HIGH: 'Price: low to high',
HIGH_TO_LOW: 'Price: high to low',
TOP_RATED: 'Top rated first'
};

const sortFunctions = {
[filters.LOW_TO_HIGH]: (offers: Offer[]) => offers.sort((offerA, offerB) => offerA.price - offerB.price),
[filters.HIGH_TO_LOW]: (offers: Offer[]) => offers.sort((offerA, offerB) => offerB.price - offerA.price),
[filters.TOP_RATED]: (offers: Offer[]) => offers.sort((offerA, offerB) => offerB.rating - offerA.rating)
};

export const getSortedOffers = (
offers: Offer[],
sortType: string
) => {
if (sortFunctions[sortType]) {
return sortFunctions[sortType](offers);
} else if (sortType === filters.POPULAR) {
return offers;
}
};

export const URL_MARKER_CURRENT =
'/img/pin-active.svg';

export const URL_MARKER_STANDART =
'/img/pin.svg';
20 changes: 10 additions & 10 deletions src/mocks/cities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@ import { City } from '../types/city';
export const CITIES: City[] = [
{
title: 'Paris',
lat: 52.3740300,
lng: 4.8896900
lat: 48.864716,
lng: 2.349014
},
{
title: 'Brussels',
lat: 52.3740300,
lng: 4.8896900
lat: 50.85034,
lng: 4.35171
},
{
title: 'Cologne',
lat: 52.3740300,
lng: 4.8896900
lat: 50.935173,
lng: 6.953101
},
{
title: 'Amsterdam',
Expand All @@ -23,12 +23,12 @@ export const CITIES: City[] = [
},
{
title: 'Hamburg',
lat: 52.3740300,
lng: 4.8896900
lat: 53.551086,
lng: 9.993682
},
{
title: 'Dusseldorf',
lat: 52.3740300,
lng: 4.8896900
lat: 51.233334,
lng: 6.783333
},
];
2 changes: 1 addition & 1 deletion src/mocks/offers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const OFFERS: Offer[] = [
isFavorite: true,
rating: 4,
reviews: [REVIEWS[1]],
city: CITIES[1],
city: CITIES[0],
point: POINTS[1]
},
{
Expand Down
12 changes: 6 additions & 6 deletions src/mocks/points.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import { Point } from '../types/point';

export const POINTS: Point[] = [
{
lat: 52.3909553943508,
lng: 4.85309666406198
lat: 48.856716,
lng: 2.369014
},
{
lat: 52.3609553943508,
lng: 4.85309666406198
lat: 48.876716,
lng: 2.349014
},
{
lat: 52.3909553943508,
lng: 4.929309666406198
lat: 48.826716,
lng: 2.319014
},
{
lat: 52.3809553943508,
Expand Down
19 changes: 3 additions & 16 deletions src/pages/main-screen/main-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Map from '../../components/map/map';
import { typeOfCardList } from '../../const';
import { useAppSelector } from '../../hooks';
import CityList from '../../components/city-list/city-list';
import CardsSortingOptions from '../../components/cards-sorting-options/cards-sorting-options';

function MainScreen(): JSX.Element {
const [city, offers] = useAppSelector((state) => [state.city, state.offers]);
Expand Down Expand Up @@ -55,26 +56,12 @@ function MainScreen(): JSX.Element {
<section className="cities__places places">
<h2 className="visually-hidden">Places</h2>
<b className="places__found">{chosenOffers.length} places to stay in {city.title}</b>
<form className="places__sorting" action="#" method="get">
<span className="places__sorting-caption">Sort by</span>
<span className="places__sorting-type" tabIndex={0}>
Popular
<svg className="places__sorting-arrow" width="7" height="4">
<use xlinkHref="#icon-arrow-select"></use>
</svg>
</span>
<ul className="places__options places__options--custom places__options--opened">
<li className="places__option places__option--active" tabIndex={0}>Popular</li>
<li className="places__option" tabIndex={0}>Price: low to high</li>
<li className="places__option" tabIndex={0}>Price: high to low</li>
<li className="places__option" tabIndex={0}>Top rated first</li>
</ul>
</form>
<CardsSortingOptions/>
<OfferList offers={chosenOffers} listType={typeOfCardList.standart}/>
</section>
<div className="cities__right-section">
<section className="cities__map map">
<Map points={points} city={city} selectedPoint={undefined}/>
<Map points={points}/>
</section>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion src/pages/offer-screen/offer-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ function OfferScreen({offer}: OfferScreenProps): JSX.Element {
</div>
</div>
<section className="offer__map map">
<Map points={[POINTS[0], POINTS[1], POINTS[2]]} city={CITIES[1]} selectedPoint={undefined}/>
<Map points={[POINTS[0], POINTS[1], POINTS[2]]} city={CITIES[1]}/>

Check failure on line 171 in src/pages/offer-screen/offer-screen.tsx

View workflow job for this annotation

GitHub Actions / build

Type '{ points: Point[]; city: City; }' is not assignable to type 'IntrinsicAttributes & MapProps'.
</section>
</section>
<div className="container">
Expand Down
9 changes: 9 additions & 0 deletions src/store/action.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
import { createAction } from '@reduxjs/toolkit';
import { City } from '../types/city';
import { Point } from '../types/point';

export const getOffers = createAction('OFFERS_GET');

export const changeCity = createAction('CITY_CHANGE', (value: City) => ({
payload: value
}));

export const changeSortOptions = createAction('CHANGE_SORT_OPTIONS', (value: string) => ({
payload: value
}));

export const changeHighlightedMarker = createAction('CHANGE_HIGHLIGHTED_MARKER', (value: Point | undefined) => ({
payload: value
}));
17 changes: 15 additions & 2 deletions src/store/reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,23 @@ import { CITIES } from '../mocks/cities';
import { OFFERS } from '../mocks/offers';
import { City } from '../types/city';
import { Offer } from '../types/offer';
import { changeCity, getOffers } from './action';
import { changeCity, changeHighlightedMarker, changeSortOptions, getOffers } from './action';
import { filters } from '../const';
import { Point } from '../types/point';


type StateType = {
city: City;
offers: Offer[];
sortType: string;
highlightedMarker?: Point;
}

const initialState: StateType = {
city: CITIES[0],
offers: OFFERS
offers: OFFERS,
sortType: filters.POPULAR,
highlightedMarker: undefined
};

const reducer = createReducer(initialState, (builder) => {
Expand All @@ -22,6 +29,12 @@ const reducer = createReducer(initialState, (builder) => {
})
.addCase(changeCity, (state, action) => {
state.city = action.payload;
})
.addCase(changeSortOptions, (state, action) => {
state.sortType = action.payload;
})
.addCase(changeHighlightedMarker, (state, action) => {
state.highlightedMarker = action.payload;
});
});

Expand Down

0 comments on commit 4dec8ce

Please sign in to comment.