Skip to content

Commit

Permalink
Merge pull request #8 from fed1v/module6-task2
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Nov 17, 2024
2 parents 07b66e5 + 0dcf46c commit 87b61cd
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 20 deletions.
23 changes: 23 additions & 0 deletions src/components/sort-options/sort-options-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import {Sorting} from '../../consts.ts';

type SortOptionsItemProps = {
option: Sorting;
isActive: boolean;
onItemClick: (option: Sorting) => void;
}

export function SortOptionsItem({option, isActive, onItemClick}: SortOptionsItemProps) {
const className = isActive
? 'places__option places__option--active'
: 'places__option';

return (
<li
className={className}
tabIndex={0}
onClick={() => onItemClick(option)}
>
{option}
</li>
);
}
55 changes: 55 additions & 0 deletions src/components/sort-options/sort-options.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {useState} from 'react';
import {Sorting} from '../../consts.ts';
import {SortOptionsItem} from './sort-options-item.tsx';
import {useAppSelector} from '../../hooks';

type SortOptionsProps = {
options: Sorting[];
onSortingOptionChange: (sortingOption: Sorting) => void;
}

export function SortOptions({options, onSortingOptionChange}: SortOptionsProps) {
const [isVisible, setIsVisible] = useState(false);

const sorting = useAppSelector((state) => state.sorting);

function handleSortingExpand() {
setIsVisible((value) => !value);
}

function handleSortingOptionChange(option: Sorting) {
onSortingOptionChange(option);
setIsVisible(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={() => handleSortingExpand()}
>
{sorting}
<svg className="places__sorting-arrow" width="7" height="4">
<use xlinkHref="#icon-arrow-select"></use>
</svg>
</span>

{isVisible &&
<ul className="places__options places__options--custom places__options--opened">
{
options.map((option) => (
<SortOptionsItem
key={option}
option={option}
isActive={option === sorting}
onItemClick={handleSortingOptionChange}
/>
))
}
</ul>}

</form>
);
}
9 changes: 8 additions & 1 deletion src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,16 @@ export enum AuthorizationStatus {
Unknown = 'UNKNOWN'
}

export enum PlaceCardType{
export enum PlaceCardType {
City,
Near
}

export const CITY_NAMES = ['Paris', 'Cologne', 'Brussels', 'Amsterdam', 'Hamburg', 'Dusseldorf'];

export enum Sorting {
POPULAR = 'Popular',
PRICE_LOW_TO_HIGH = 'Price: low to high',
PRICE_HIGH_TO_LOW = 'Price: high to low',
TOP_RATED_FIRST = 'Top rated first',
}
34 changes: 17 additions & 17 deletions src/pages/main-screen/main-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import {Header} from '../../components/header/header.tsx';
import {CityPlaceCardList} from '../../components/place-card/place-card-list.tsx';
import {CitiesList} from '../../components/cities-list/cities-list.tsx';
import {useAppDispatch, useAppSelector} from '../../hooks';
import {selectCity} from '../../store/action.ts';
import {applySorting, selectCity} from '../../store/action.ts';
import {SortOptions} from '../../components/sort-options/sort-options.tsx';
import {Sorting} from '../../consts.ts';
import {applySortingToOffersList} from '../../store/sorting.ts';

type MainScreenProps = {
cityNames: string[];
Expand All @@ -18,14 +21,21 @@ export function MainScreen({cityNames}: MainScreenProps) {

const cityName = useAppSelector((state) => state.city);
const offers = useAppSelector((state) => state.offers);
const sorting = useAppSelector((state) => state.sorting);

const currentOffers = offers.filter((offer) => offer.city.name === cityName);
let currentOffers = offers.filter((offer) => offer.city.name === cityName);

currentOffers = applySortingToOffersList(sorting, currentOffers);

function handleActiveOfferChange(id: Nullable<string>) {
const newActiveOffer = currentOffers.find((offer) => offer.id === id);
setActiveOffer(newActiveOffer);
}

function handleSortingOptionChange(newSorting: Sorting) {
dispatch(applySorting({sorting: newSorting}));
}

return (
<div className="page page--gray page--main">
<Header/>
Expand All @@ -44,21 +54,11 @@ export function MainScreen({cityNames}: MainScreenProps) {
<section className="cities__places places">
<h2 className="visually-hidden">Places</h2>
<b className="places__found">{currentOffers.length} places to stay in {cityName}</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>

<SortOptions
options={Object.values(Sorting)}
onSortingOptionChange={handleSortingOptionChange}
/>
<CityPlaceCardList
offers={currentOffers}
onActiveItemChange={handleActiveOfferChange}
Expand Down
3 changes: 3 additions & 0 deletions src/store/action.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import {createAction} from '@reduxjs/toolkit';
import {Offer} from '../types/offer.ts';
import {Sorting} from '../consts.ts';

export const selectCity = createAction<{ city: string }>('selectCity');

export const fillOffersList = createAction<{ offers: Offer[] }>('fillOffersList');

export const applySorting = createAction<{ sorting: Sorting }>('applySorting');
9 changes: 7 additions & 2 deletions src/store/reducer.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import {createReducer} from '@reduxjs/toolkit';
import {fillOffersList, selectCity} from './action.ts';
import {applySorting, fillOffersList, selectCity} from './action.ts';
import {Offer} from '../types/offer.ts';
import {CITY_NAMES} from '../consts.ts';
import {CITY_NAMES, Sorting} from '../consts.ts';

const initialState: {
city: string;
offers: Offer[];
sorting: Sorting;
} = {
city: CITY_NAMES[0],
offers: [],
sorting: Sorting.POPULAR
};

export const reducer = createReducer(initialState, (builder) => {
Expand All @@ -18,5 +20,8 @@ export const reducer = createReducer(initialState, (builder) => {
})
.addCase(fillOffersList, (state, action) => {
state.offers = action.payload.offers;
})
.addCase(applySorting, (state, action) => {
state.sorting = action.payload.sorting;
});
});
19 changes: 19 additions & 0 deletions src/store/sorting.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import {Sorting} from '../consts.ts';
import {Offer} from '../types/offer.ts';

export function applySortingToOffersList(sorting: Sorting, offers: Offer[]) {
switch (sorting) {
case Sorting.POPULAR: {
return offers;
}
case Sorting.PRICE_HIGH_TO_LOW: {
return offers.toSorted((a, b) => b.price - a.price);
}
case Sorting.PRICE_LOW_TO_HIGH: {
return offers.toSorted((a, b) => a.price - b.price);
}
case Sorting.TOP_RATED_FIRST: {
return offers.toSorted((a, b) => a.rating - b.rating);
}
}
}

0 comments on commit 87b61cd

Please sign in to comment.