Skip to content

Commit

Permalink
Merge pull request #30 from web-Nearest-car-wash/feature/popupWithFil…
Browse files Browse the repository at this point in the history
…ters

Feature/popupWithFilters
  • Loading branch information
JayWeee authored Feb 1, 2024
2 parents 1194863 + ecb6b9d commit 4587e21
Show file tree
Hide file tree
Showing 21 changed files with 599 additions and 30 deletions.
163 changes: 163 additions & 0 deletions src/components/PopupWithFilters/PopupWithFilters.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import styles from './PopupWithFilters.module.css';
import stylesButton from '../UI/ServiceButton/ServiceButton.module.css';
import FilterWithCheckbox from '../UI/FilterWithCheckbox/FilterWithCheckbox';
import FilterWithServices from '../UI/FilterWithServices/FilterWithServices';
import RemoveSearch from '../UI/icons/RemoveSearch';
import ClearFilters from '../UI/icons/ClearFilters';
import {
fetchListServices,
fetchListTypes,
selectFilters,
handleOpen,
} from '../../store/filters/filters-slice';
import { fetchListFilteredCarWashes } from '../../store/carWashes/carWashes-slice';

function PopupWithFilters() {
const dispatch = useDispatch();
const { listServices, listTypes, opened } = useSelector(selectFilters);
const [checkedOpened, setCheckedOpened] = useState(false);
const [checkedAroundClock, setCheckedAroundClock] = useState(false);
const [checkedRaiting, setCheckedRaiting] = useState(false);
const [arrServiceButtons, setArrServiceButtons] = useState([]);
const [arrFilters, setArrFilters] = useState([]);

const styleActive = stylesButton.active;

const request = {
opened: checkedOpened ? `is_open=${checkedOpened}&` : '',
aroundClock: checkedAroundClock
? `is_around_the_clock=${checkedAroundClock}&`
: '',
raiting: checkedRaiting ? `high_rating=${checkedRaiting}&` : '',
services:
arrFilters.length > 0 ? `services=${encodeURI(arrFilters.join())}&` : '',
};

const handleChangeOpened = () => {
setCheckedOpened(!checkedOpened);
};

const handleChangeAroundClock = () => {
setCheckedAroundClock(!checkedAroundClock);
};

const handleChangeRaiting = () => {
setCheckedRaiting(!checkedRaiting);
};

const handleClickFilterButton = (e) => {
const { classList, id, value } = e.target;
if (classList.contains(styleActive)) {
classList.remove(styleActive);
setArrServiceButtons(arrServiceButtons.filter((item) => item.id !== id));
setArrFilters(arrFilters.filter((i) => i !== value));
} else {
classList.add(styleActive);
setArrServiceButtons([...arrServiceButtons, { id }]);
setArrFilters([...arrFilters, value]);
}
};

const handleApplyfilters = () => {
dispatch(
fetchListFilteredCarWashes(
`${request.opened}${request.aroundClock}${request.raiting}${request.services}`
)
);
};

const handleClearFilters = () => {
setCheckedOpened(false);
setCheckedAroundClock(false);
setCheckedRaiting(false);
arrServiceButtons.map((item) =>
document.getElementById(item.id).classList.remove(styleActive)
);
dispatch(
fetchListFilteredCarWashes(
`${request.opened}&${request.aroundClock}&${request.raiting}&${request.services}`
)
);
};

useEffect(() => {
dispatch(fetchListServices());
dispatch(fetchListTypes());
}, [dispatch]);

useEffect(() => {
const closePopupHandler = (e) => {
if (e.target.classList.contains(styles.opened)) {
dispatch(handleOpen(false));
}
};

document.addEventListener('click', closePopupHandler);
return () => {
document.removeEventListener('click', closePopupHandler);
};
}, [dispatch]);

return (
<div className={opened ? `${styles.popup} ${styles.opened}` : styles.popup}>
<div className={styles.container}>
<button
className={styles.close}
aria-label="Кнопка закрытия попапа"
onClick={() => dispatch(handleOpen(false))}
>
<RemoveSearch />
</button>
<h2 className={styles.header}>Фильтр</h2>
<div className={styles.filters}>
<FilterWithCheckbox
onChange={handleChangeOpened}
checked={checkedOpened}
filterName="Открыто сейчас"
/>
<FilterWithCheckbox
onChange={handleChangeAroundClock}
checked={checkedAroundClock}
filterName="Круглосуточно"
/>
<FilterWithServices
title="Услуга"
services={listServices}
onClick={handleClickFilterButton}
/>
<FilterWithServices
title="Формат"
services={listTypes}
onClick={handleClickFilterButton}
/>
<FilterWithCheckbox
onChange={handleChangeRaiting}
checked={checkedRaiting}
filterName="Рейтинг 4+"
/>
</div>
<div className={styles.buttons}>
<button
className={styles.clear}
aria-label="Очистить фильтры"
onClick={handleClearFilters}
>
<ClearFilters />
Очистить фильтры
</button>
<button
className={styles.apply}
aria-label="Применить фильтры"
onClick={handleApplyfilters}
>
Применить фильтры
</button>
</div>
</div>
</div>
);
}

export default PopupWithFilters;
111 changes: 111 additions & 0 deletions src/components/PopupWithFilters/PopupWithFilters.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
.popup {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
background-color: rgba(144, 144, 144, 0.5);
opacity: 0;
visibility: hidden;
}

.opened {
opacity: 1;
visibility: visible;
}

.container {
font-family: 'Roboto', Arial, sans-serif;
font-size: 20px;
font-weight: 500;
background-color: #fff;
padding: 24px;
box-sizing: border-box;
max-width: 575px;
width: 100%;
border-radius: 15px;
display: flex;
flex-direction: column;
align-items: center;
position: fixed;
top: 100px;
left: 125px;
}

.close {
border: none;
background-color: inherit;
align-self: flex-end;
cursor: pointer;
padding: 0;
}

.header {
margin: 0;
font-family: 'Manrope', Arial, sans-serif;
font-size: 24px;
font-weight: 700;
line-height: normal;
padding-top: 20px;
}

.filters {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
gap: 28px;
max-height: 400px;
overflow-y: scroll;
}

.filters::-webkit-scrollbar {
display: none;
}

.filter {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0;
width: 100%;
}

.buttons {
display: flex;
justify-content: space-between;
width: 100%;
align-items: center;
margin-top: 32px;
}

.clear {
border: none;
cursor: pointer;
background-color: inherit;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
padding: 0;
color: #7b7b7b;
font-family: 'Roboto', Arial, sans-serif;
font-size: 20px;
font-weight: 500;
line-height: normal;
}

.apply {
border: none;
cursor: pointer;
background-color: #5568d0;
padding: 0;
color: white;
font-family: 'Roboto', Arial, sans-serif;
font-size: 20px;
font-weight: 500;
line-height: normal;
padding: 8px 16px;
border-radius: 10px;
}
12 changes: 4 additions & 8 deletions src/components/UI/FilterButton/FilterButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ import PropTypes from 'prop-types';
import styles from './FilterButton.module.css';
import IconFilter from '../icons/IconFilter';

function FilterButton({ handleClick, numberOfFilters }) {
function FilterButton({ onClick, numberOfFilters }) {
return (
<div className={styles.filter}>
<button
aria-label="Фильтр"
className={styles.button}
onClick={handleClick}
>
<button aria-label="Фильтр" className={styles.button} onClick={onClick}>
<IconFilter />
</button>
<p
Expand All @@ -27,12 +23,12 @@ function FilterButton({ handleClick, numberOfFilters }) {
}

FilterButton.propTypes = {
handleClick: PropTypes.func,
onClick: PropTypes.func,
numberOfFilters: PropTypes.number,
};

FilterButton.defaultProps = {
handleClick: () => {},
onClick: () => {},
numberOfFilters: 0,
};

Expand Down
1 change: 1 addition & 0 deletions src/components/UI/FilterButton/FilterButton.module.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.filter {
height: 44px;
width: 44px;
display: flex;
}

Expand Down
25 changes: 25 additions & 0 deletions src/components/UI/FilterWithCheckbox/FilterWithCheckbox.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import styles from './FilterWithCheckbox.module.css';
import ServiceCheckbox from '../ServiceCheckbox/ServiceCheckbox';

function FilterWithCheckbox({ filterName, onChange, checked }) {
return (
<p className={styles.filter}>
{filterName}
<ServiceCheckbox checked={checked} onChange={onChange} />
</p>
);
}

FilterWithCheckbox.propTypes = {
filterName: PropTypes.string,
onChange: PropTypes.func,
checked: PropTypes.bool,
};

FilterWithCheckbox.defaultProps = {
filterName: '',
};

export default FilterWithCheckbox;
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.filter {
display: flex;
justify-content: space-between;
align-items: center;
margin: 0;
width: 100%;
}
28 changes: 28 additions & 0 deletions src/components/UI/FilterWithServices/FilterWithServices.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import PropTypes from 'prop-types';
import styles from './FilterWithServices.module.css';
import ServiceButton from '../ServiceButton/ServiceButton';

function FilterWithServices({ title, services, onClick }) {
return (
<div className={styles.container}>
<h2 className={styles.title}>{title}</h2>
<div className={styles.filters}>
{services.map((service) => (
<ServiceButton
key={service.name}
value={service.name.toLowerCase()}
onClick={onClick}
/>
))}
</div>
</div>
);
}

FilterWithServices.propTypes = {
onClick: PropTypes.func,
title: PropTypes.string,
services: PropTypes.arrayOf(PropTypes.objectOf(PropTypes.string)),
};

export default FilterWithServices;
Loading

0 comments on commit 4587e21

Please sign in to comment.