Skip to content

Commit

Permalink
Merge pull request #77 from MargoMarm/feature/products-filter
Browse files Browse the repository at this point in the history
Feature/products filter
  • Loading branch information
TaurusVB committed Sep 23, 2023
2 parents bad7a17 + 6620d11 commit c8707ec
Show file tree
Hide file tree
Showing 13 changed files with 198 additions and 67 deletions.
1 change: 1 addition & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"date-fns": "^2.30.0",
"dayjs": "^1.11.9",
"formik": "^2.4.4",
"lodash.debounce": "^4.0.8",
"modern-normalize": "^2.0.0",
"notiflix": "^3.2.6",
"overlayscrollbars": "^2.3.1",
Expand Down
3 changes: 3 additions & 0 deletions src/assets/shewron.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions src/assets/sprite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions src/components/DailyStatsCards/DailyStatsCards.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@ const DailyStatsCards = ({
);
};

DailyStatsCards.propTypes = {
icon: PropTypes.string.isRequired,
keyValue: PropTypes.any.isRequired,
label: PropTypes.string.isRequired,
border: PropTypes.oneOf(['green', 'red', "default"]),
fill: PropTypes.oneOf(['true', 'false']),
};
// DailyStatsCards.propTypes = {
// icon: PropTypes.string.isRequired,
// keyValue: PropTypes.any.isRequired,
// label: PropTypes.string.isRequired,
// border: PropTypes.oneOf(['green', 'red', "default"]),
// fill: PropTypes.oneOf(['true', 'false']),
// };

export default DailyStatsCards;
104 changes: 91 additions & 13 deletions src/components/ProductsFilter/ProductsFilter.jsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,103 @@
import sprite from '../../assets/sprite.svg';
import ButtonIconForInput from '../ButtonIconForInput';
import productsCategories from '../../data/productsCategories.json';

// import productsCategories from '../../data/productsCategories.json';
import { useDispatch, useSelector } from 'react-redux';
import { useEffect, useState } from 'react';
import { getProductsCategories } from '../../redux/productsFilter/selectors';
import { getCategories, fetchProducts } from "../../redux/productsFilter/operations";
import {
FilterContainer,
SelectContainer,
TextInput,
Select,
Option,
InputWrapper,
SelectPointer,
Svg,
FilterTitle,
} from './ProductsFilter.styled';
import debounce from 'lodash.debounce';



export default function ProductsFilter() {
const makeReqObj = (input, category, recommended) => {
const reqObj = {};

if (input) {
reqObj.title = input;
}
if (category && category !== 'Categories' && category !== "default") {
reqObj.category = category;
}

if (recommended === 'Recommended') {
reqObj.recommended = true;
}
if (recommended === 'Not recommended') {
reqObj.recommended = false;
}
return reqObj;
};
const dispatch = useDispatch()
const [currentCategory, setCurrentCategory] = useState("Categories");
const [isRecommended, setIsRecommended] = useState("All")
const [query, setQuery] = useState("");

const productsCategories = useSelector(getProductsCategories);
useEffect(() => {
const reqObj = makeReqObj(query, currentCategory, isRecommended);
const urlParams = new URLSearchParams(reqObj).toString();
dispatch(fetchProducts(urlParams))
}, [query, currentCategory, isRecommended, dispatch ] )


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

const handleChangeCategory = event => {
const selectedValue = event.target.value;
setCurrentCategory(selectedValue)
}
const debouncedHandleChange = debounce((term) => {
setQuery(term)
}, 500);

const handleChangeQuery = event => {
const selectedValue = event.target.value;
debouncedHandleChange(selectedValue);
}
const handleChangeisReccomended = event => {
const selectedValue = event.target.value;
setIsRecommended(selectedValue)
}

const optionStyles = {
backgroundColor: 'rgba(28, 28, 28, 1)',
color: "#EFEDE8",
fontSize: "16px",
lineHeight: "24px",
};
const handleSubmit = event => {
event.preventDefault();
}

return (
<FilterContainer>
<FilterTitle>Filters</FilterTitle>
<InputWrapper>
<TextInput type="text" autoComplete="off" />
<InputWrapper >
<TextInput type="text" autoComplete="off" onSubmit={handleSubmit} onChange={handleChangeQuery} />
<ButtonIconForInput
onClick={e => console.log(e)}
right="42px"
type="submit"
type="reset"
>
<Svg>
<use href={sprite + `#close`}></use>
</Svg>
</ButtonIconForInput>
<ButtonIconForInput
onClick={e => console.log(e)}

right="18px"
type="submit"
>
Expand All @@ -38,20 +107,29 @@ export default function ProductsFilter() {
</ButtonIconForInput>
</InputWrapper>
<SelectContainer>
<Select>
<SelectPointer>
<Select value={currentCategory} onChange={handleChangeCategory}>
<option style={optionStyles} value="default">Categories</option>
{productsCategories.map(category => {
return (
<option key={category} value={category}>
<option key={category} value={category} style={optionStyles}>
{category}
</option>

);
})}

</Select>
<Select>
<option value="All">All</option>
<option value="Recommended">Recommended</option>
<option value="Not recomended">Not recommended</option>
</SelectPointer>
<SelectPointer>
<Select value={isRecommended} onChange={handleChangeisReccomended}>
<option style={optionStyles} value="default" >All</option>
<option style={optionStyles} value="Recommended">Recommended</option>
<option style={optionStyles} value="Not recommended">Not recommended</option>
</Select>
</SelectPointer>


</SelectContainer>
</FilterContainer>
);
Expand Down
82 changes: 61 additions & 21 deletions src/components/ProductsFilter/ProductsFilter.styled.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,51 @@
import styled from '@emotion/styled';
import { colors, mq } from '../../utils';



export const Option = styled.option`
width: '200px',
padding: '10px',
fontSize: '16px',
border: '1px solid #ccc',
borderRadius: '4px',
backgroundColor: '#fff',
appearance: 'none',
cursor: 'pointer',
`


export const Select = styled.select`
appearance: none;
position: reletive;
height: 46px;
width: 100%;
${mq.tablet} {
height: 52px;
}
padding-left: 14px;
padding-right: 14px;
border-radius: 12px;
border: 1px solid ${colors.textWhite03};
font-size: 16px;
font-weight: 400;
line-height: 150%;
outline: none;
color: ${colors.textWhite06};
background-color: transparent;
}
`;



export const FilterContainer = styled.div`
position: relative;
display: flex;
Expand Down Expand Up @@ -29,9 +74,24 @@ export const FilterTitle = styled.div`
export const SelectContainer = styled.div`
display: flex;
gap: 16px;
`;

export const InputWrapper = styled.div`
export const SelectPointer = styled.div`
position: relative;
&::after {
content: " ";
background-image: url('../../assets/shewron.svg');
color: red;
position: absolute;
top: 50%;
right: 14px;
transform: translateY(-50%);
pointer-events: none;
}
`

export const InputWrapper = styled.form`
position: relative;
width: 100%;
${mq.tablet} {
Expand Down Expand Up @@ -69,24 +129,4 @@ export const Svg = styled.svg`
height: 18px;
`;

export const Select = styled.select`
height: 46px;
width: 100%;
${mq.tablet} {
height: 52px;
}
padding-left: 14px;
padding-right: 14px;
border-radius: 12px;
border: 1px solid ${colors.textWhite03};

font-size: 16px;
font-weight: 400;
line-height: 150%;
outline: none;
color: ${colors.textWhite06};
background-color: transparent;
`;
2 changes: 1 addition & 1 deletion src/pages/Diary/Diary.styled.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const CalendarContainer = styled.div`
display: flex;
position: absolute;
align-items: center;
z-index: 999;
z-index: 667;
right: 20px;
top: 4px;
Expand Down
2 changes: 1 addition & 1 deletion src/pages/Products/Products.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const Products = () => {
if (i < 20) {
return (
<ProductsOrExercisesItem
key={product._id}
key={product.id}
page="product"
data={product}
/>
Expand Down
11 changes: 5 additions & 6 deletions src/redux/diary/slice.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ const diary = createSlice({
builder.addCase(getDiaryList.pending, handlePending);
builder.addCase(getDiaryList.fulfilled, (state, { payload }) => {
state.isLoading = false;
state.products = payload.products;
state.exercises = payload.exercises;
state.burnedCalories = payload.burnedCalories;
state.consumedCalories = payload.consumedCalories;
state.doneExercisesTime = payload.doneExercisesTime;
});
state.products = payload.products || [];
state.exercises = payload.exercises || [];
state.burnedCalories = payload.burnedCalories || 0;
state.consumedCalories = payload.consumedCalories || 0;
state.doneExercisesTime = payload.doneExercisesTime || 0})
builder.addCase(getDiaryList.rejected, (state, { payload }) => {
state.productsAndExercisesError = payload;
state.isLoading = false;
Expand Down
18 changes: 11 additions & 7 deletions src/redux/productsFilter/operations.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,26 @@ import axios from 'axios';

export const fetchProducts = createAsyncThunk(
`filter/getProducts`,
async (_, thunkAPI) => {
async (searchParams, thunkAPI) => {
try {
const res = await axios.get(`api/products`);
const res = await axios.get(`api/products?${searchParams}`);
return res.data;
} catch (error) {
return thunkAPI.rejectWithValue(error.message);
}
},
);

export const fetchFilteredProducts = createAsyncThunk(
`filter/getFilteredProducts`,
async (searchParams, thunkAPI) => {


export const getCategories = createAsyncThunk(
`categories/getCategories`,
async (_, thunkAPI) => {
try {
const res = await axios.get(`api/products&${searchParams}`);
return res.data;
const res = await axios.get("api/categories");

return res.data[0].categories;

} catch (error) {
return thunkAPI.rejectWithValue(error.message);
}
Expand Down
1 change: 1 addition & 0 deletions src/redux/productsFilter/selectors.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export const getProducts = state => state.products.products;
export const getProductsCategories = state => state.products.categories;
Loading

0 comments on commit c8707ec

Please sign in to comment.