generated from goitacademy/react-homework-template
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15 from Mayotopia04/mitch-diary
Mitch - Modified codes in the diary page and diary components.
- Loading branch information
Showing
11 changed files
with
813 additions
and
109 deletions.
There are no files selected for viewing
148 changes: 142 additions & 6 deletions
148
src/components/DiaryAddProductForm/DiaryAddProductForm.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,145 @@ | ||
import React from 'react'; | ||
import React, { useState, useEffect, useMemo } from 'react'; | ||
import { useSelector, useDispatch } from 'react-redux'; | ||
import Select from 'react-select'; | ||
import debounce from 'lodash.debounce'; | ||
|
||
import { getProductsByQuery, addMeal } from '../../redux/products/products-operations'; | ||
import useWindowDimensions from '../../services/hooks/useWindowDimensions'; | ||
import { Button, ButtonPlus } from 'components'; | ||
import s from './DiaryAddProductForm.module.css'; | ||
|
||
const DiaryAddProductForm = () => { | ||
return ( | ||
<div>DiaryAddProductForm</div> | ||
) | ||
} | ||
const { productsOptions, date } = useSelector(state => state.products); | ||
const { userDailyDiet } = useSelector(state => state.auth); | ||
const { width } = useWindowDimensions(); | ||
const dispatch = useDispatch(); | ||
|
||
const [product, setProduct] = useState(''); | ||
const [weight, setWeight] = useState(''); | ||
const [selectedOption, setSelectedOption] = useState(null); | ||
const [clarification, setСlarification] = useState(false); | ||
|
||
const selectOptions = productsOptions.map(i => { | ||
if (userDailyDiet?.notAllowedProduct?.find(item => item.title === i.title)) { | ||
return { | ||
value: i.title, | ||
label: `${i.title} *`, | ||
color: 'rgba(251, 192, 65, 0.3)', | ||
}; | ||
} else { | ||
return { | ||
value: i.title, | ||
label: i.title, | ||
}; | ||
} | ||
}); | ||
|
||
const getProductsOptions = useMemo( | ||
() => | ||
debounce(value => { | ||
dispatch(getProductsByQuery(value)); | ||
}, 400), | ||
[dispatch] | ||
); | ||
|
||
useEffect(() => { | ||
if (!product) return; | ||
getProductsOptions(product); | ||
setСlarification(true); | ||
}, [product, getProductsOptions]); | ||
|
||
const handleSelectChange = value => { | ||
setProduct(value); | ||
}; | ||
|
||
const handleInputChange = e => { | ||
setWeight(e.target.value); | ||
}; | ||
|
||
const handleFormSubmit = e => { | ||
e.preventDefault(); | ||
|
||
const newMeal = { | ||
date, | ||
product: selectedOption.value, | ||
grams: weight, | ||
}; | ||
|
||
dispatch(addMeal(newMeal)); | ||
|
||
setProduct(''); | ||
setWeight(''); | ||
setSelectedOption(null); | ||
}; | ||
|
||
const colourStyles = { | ||
option: (styles, { data }) => { | ||
return { | ||
...styles, | ||
backgroundColor: data.color ? data.color : 'transparent', | ||
}; | ||
}, | ||
}; | ||
|
||
return ( | ||
<> | ||
<form className={s.form} onSubmit={handleFormSubmit}> | ||
{clarification && ( | ||
<p className={s.clarification}> | ||
* Items on the orange background in the drop down list are not recommended for your | ||
diet. | ||
</p> | ||
)} | ||
<label className={s.label}> | ||
<Select | ||
// common | ||
name="product" | ||
required | ||
placeholder="Enter product name" | ||
// for input | ||
isSearchable={true} | ||
inputValue={product} | ||
onInputChange={handleSelectChange} | ||
// for select | ||
defaultValue={selectedOption} | ||
value={selectedOption} | ||
onChange={setSelectedOption} | ||
// for menu (list of options) | ||
options={selectOptions} | ||
menuIsOpen={product.length > 0} | ||
onMenuClose={() => setСlarification(false)} | ||
// for styles | ||
unstyled | ||
classNamePrefix="react-select" | ||
styles={colourStyles} | ||
|
||
/> | ||
</label> | ||
|
||
<label className={s.label}> | ||
<input | ||
type="number" | ||
name="weight" | ||
value={weight} | ||
min="0" | ||
max="3000" | ||
required | ||
placeholder="Grams" | ||
className={s.input} | ||
onChange={handleInputChange} | ||
/> | ||
</label> | ||
|
||
|
||
|
||
|
||
{width < 768 && <Button text="Add" width={176} />} | ||
|
||
{width > 767 && <ButtonPlus />} | ||
|
||
</form> | ||
</> | ||
); | ||
}; | ||
|
||
export default DiaryAddProductForm; | ||
export default DiaryAddProductForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
.form { | ||
position: relative; | ||
display: flex; | ||
flex-direction: column; | ||
align-items: center; | ||
width: 280px; | ||
} | ||
|
||
.clarification { | ||
position: absolute; | ||
top: -40px; | ||
left: 0; | ||
margin-bottom: 10px; | ||
color: var(--second-color); | ||
font-size: 10px; | ||
} | ||
|
||
.label { | ||
width: 100%; | ||
} | ||
|
||
.input { | ||
width: 100%; | ||
padding: 8px 0; | ||
border: none; | ||
/* color */ | ||
color: var(--second-color); | ||
border-bottom: 1px solid var(--border-color); | ||
/* font */ | ||
font-weight: 700; | ||
line-height: 1.21; | ||
} | ||
|
||
.input:focus, | ||
.input:hover { | ||
outline: none; | ||
border-bottom: 1px solid var(--accent-color); | ||
} | ||
|
||
.input::placeholder { | ||
color: var(--second-color); | ||
} | ||
|
||
@media screen and (max-width: 320px) { | ||
.form { | ||
width: 100%; | ||
} | ||
} | ||
|
||
@media screen and (max-width: 767px) { | ||
.form { | ||
margin: 0 auto; | ||
} | ||
|
||
.clarification { | ||
max-width: 280px; | ||
margin-left: auto; | ||
margin-right: auto; | ||
text-align: center; | ||
} | ||
|
||
.label { | ||
margin-bottom: 24px; | ||
} | ||
|
||
.label:last-of-type { | ||
margin-bottom: 60px; | ||
} | ||
} | ||
|
||
@media screen and (min-width: 768px) { | ||
.form { | ||
flex-direction: row; | ||
align-items: flex-end; | ||
|
||
margin-bottom: 40px; | ||
min-width: 455px; | ||
} | ||
|
||
.clarification { | ||
top: -25px; | ||
} | ||
|
||
.label { | ||
flex-shrink: 0; | ||
width: 240px; | ||
margin-right: 20px; | ||
} | ||
|
||
.label:last-of-type { | ||
width: 105px; | ||
margin-right: 85px; | ||
} | ||
|
||
.label:last-of-type .input { | ||
text-align: end; | ||
} | ||
|
||
.input { | ||
flex-shrink: 0; | ||
padding: 20px 0; | ||
} | ||
} | ||
|
||
@media screen and (min-width: 1280px) { | ||
.label { | ||
margin-right: 50px; | ||
} | ||
|
||
.label:last-of-type { | ||
margin-right: 60px; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* Styles for React select */ | ||
|
||
div.react-select__control { | ||
width: 100%; | ||
padding: 8px 0; | ||
border-radius: 0; | ||
/* color */ | ||
border: none; | ||
color: var(--second-color); | ||
border-bottom: 1px solid var(--border-color); | ||
} | ||
|
||
div.react-select__control:hover { | ||
outline: none; | ||
border: none; | ||
border-color: none; | ||
border-bottom: 1px solid var(--accent-color); | ||
box-shadow: none; | ||
} | ||
|
||
div.react-select__control--is-focused { | ||
outline: none; | ||
border: none; | ||
border-color: none; | ||
border-bottom: 1px solid var(--accent-color); | ||
box-shadow: none; | ||
} | ||
|
||
div.react-select__value-container { | ||
padding: 0; | ||
text-align: start; | ||
} | ||
|
||
div.react-select__single-value { | ||
color: inherit; | ||
} | ||
|
||
div.react-select__placeholder { | ||
color: inherit; | ||
text-align: start; | ||
} | ||
|
||
div.react-select__input-container { | ||
padding: 0; | ||
margin: 0; | ||
color: inherit; | ||
} | ||
|
||
input.react-select__input { | ||
padding: 0; | ||
font-weight: 700; | ||
line-height: 1.21; | ||
width: 500px; | ||
} | ||
|
||
div.react-select__indicators { | ||
display: none; | ||
} | ||
|
||
div.react-select__menu-list::-webkit-scrollbar { | ||
width: 6px; | ||
} | ||
|
||
div.react-select__menu-list::-webkit-scrollbar-track { | ||
padding-left: 20px; | ||
background-color: var(--scroll-color); | ||
} | ||
|
||
div.react-select__menu-list::-webkit-scrollbar-thumb { | ||
background-color: var(--third-color); | ||
} | ||
|
||
div.react-select__option--is-focused { | ||
color: var(--third-color); | ||
} | ||
|
||
@media screen and (min-width: 768px) { | ||
div.react-select__control { | ||
flex-shrink: 0; | ||
padding: 20px 0; | ||
} | ||
div.react-select__menu { | ||
width: 365px; | ||
} | ||
} | ||
|
||
@media screen and (min-width: 768px) { | ||
div.react-select__menu { | ||
width: 395px; | ||
} | ||
} | ||
|
Oops, something went wrong.