| @@ -1,4 +1,4 @@ | |||
| import React, { useState } from "react"; | |||
| import React, { useEffect, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| ContentContainer, | |||
| @@ -11,69 +11,32 @@ import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcat | |||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as CategoryChosen } from "../../../assets/images/svg/category-chosen.svg"; | |||
| import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | |||
| import Link from "../../Link/Link"; | |||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | |||
| import FilterCheckboxDropdown from "./FilterDropdown/Checkbox/FilterCheckboxDropdown"; | |||
| import Mockupdata from "./Mockupdata"; | |||
| // import { useState } from "react"; | |||
| import FilterRadioDropdown from "./FilterDropdown/Radio/FilterRadioDropdown"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { HOME_PAGE } from "../../../constants/pages"; | |||
| import qs from "query-string"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import selectedTheme from "../../../themes"; | |||
| import useFilters from "../../../hooks/useFilters"; | |||
| const FilterCard = () => { | |||
| const history = useHistory(); | |||
| const { t } = useTranslation(); | |||
| const [isOpened, setIsOpened] = useState(false); | |||
| const [isDisabled, setIsDisabled] = useState(true); | |||
| const filters = useFilters(); | |||
| // useEffect(() => { | |||
| // const queryString = history.location.search.substring(1); | |||
| // const queryObject = qs.parse(queryString); | |||
| // if (queryObject.category) { | |||
| // setSelectedCategory( | |||
| // Mockupdata[1].find( | |||
| // (item) => item.string === queryObject.category.toString() | |||
| // ).id | |||
| // ); | |||
| // } | |||
| // if (queryObject.subcategory) { | |||
| // setSelectedSubcategory( | |||
| // Mockupdata[1].find( | |||
| // (item) => item.string === queryObject.subcategory.toString() | |||
| // ).id | |||
| // ); | |||
| // } | |||
| // if (queryObject.city) { | |||
| // let filters = []; | |||
| // if (Array.isArray(queryObject.city)) { | |||
| // queryObject.city.forEach((item) => { | |||
| // filters.push(Mockupdata[0].find((p) => p.string === item).id); | |||
| // }); | |||
| // } else { | |||
| // filters.push( | |||
| // Mockupdata[0].find((p) => p.string === queryObject.city).id | |||
| // ); | |||
| // } | |||
| // setfilters.selectedLocations([...filters]); | |||
| // } | |||
| // }, []); | |||
| const handleSelectCategory = (category) => { | |||
| filters.setSelectedCategory(category); | |||
| filters.setSelectedSubcategory(); | |||
| if (category?._id === 0) { | |||
| useEffect(() => { | |||
| if (!filters.selectedCategory || filters.selectedCategory?._id === 0) { | |||
| setIsOpened(false); | |||
| setIsDisabled(true); | |||
| } else { | |||
| setIsDisabled(false); | |||
| } | |||
| }, [filters.selectedCategory]) | |||
| const handleSelectCategory = (category) => { | |||
| filters.setSelectedCategory(category); | |||
| filters.setSelectedSubcategory(); | |||
| } | |||
| const handleOpen = () => { | |||
| @@ -81,54 +44,10 @@ const FilterCard = () => { | |||
| } | |||
| const handleFilters = () => { | |||
| let queryObject = {}; | |||
| if (filters.selectedCategory !== 0) { | |||
| queryObject = { | |||
| category: Mockupdata[1].find( | |||
| (item) => item.id.toString() === filters.selectedCategory.toString() | |||
| ).string, | |||
| }; | |||
| if (filters.selectedSubcategory !== 0) { | |||
| queryObject = { | |||
| ...queryObject, | |||
| subcategory: Mockupdata[1].find( | |||
| (item) => | |||
| item.id.toString() === filters.selectedSubcategory.toString() | |||
| ).string, | |||
| }; | |||
| } | |||
| } | |||
| if (filters.selectedLocations.length > 0) { | |||
| let arrayObject = []; | |||
| filters.selectedLocations.forEach((item) => { | |||
| arrayObject.push( | |||
| Mockupdata[0].find((p) => p.id.toString() === item.toString()).string | |||
| ); | |||
| }); | |||
| queryObject = { ...queryObject, city: arrayObject }; | |||
| } | |||
| const queryString = qs.stringify(queryObject); | |||
| history.push({ | |||
| pathname: HOME_PAGE, | |||
| search: "?" + queryString, | |||
| }); | |||
| window.scrollTo({ | |||
| top: 0, | |||
| behavior: "smooth", | |||
| }); | |||
| filters.applyFilters(); | |||
| }; | |||
| const clearFilters = () => { | |||
| filters.setSelectedLocations([]); | |||
| filters.setSelectedCategory(0); | |||
| filters.setSelectedSubcategory(0); | |||
| history.push({ | |||
| pathname: HOME_PAGE, | |||
| search: "", | |||
| }); | |||
| window.scrollTo({ | |||
| top: 0, | |||
| behavior: "smooth", | |||
| }); | |||
| filters.clearFilters(); | |||
| }; | |||
| return ( | |||
| @@ -147,7 +66,7 @@ const FilterCard = () => { | |||
| <ContentContainer> | |||
| {/* Categories */} | |||
| <FilterRadioDropdown | |||
| data={[...filters.categories]} | |||
| data={[...filters?.categories]} | |||
| icon={ | |||
| filters.selectedCategory?.name ? <CategoryChosen /> : <Category /> | |||
| } | |||
| @@ -186,7 +105,7 @@ const FilterCard = () => { | |||
| <FilterCheckboxDropdown | |||
| searchPlaceholder={t("filters.location.placeholder")} | |||
| data={[...filters.locations]} | |||
| filters={filters.selectedLocations} | |||
| filters={[...filters.selectedLocations]} | |||
| icon={<Location />} | |||
| title={t("filters.location.title")} | |||
| setItemsSelected={filters.setSelectedLocations} | |||
| @@ -215,6 +134,7 @@ const FilterCard = () => { | |||
| FilterCard.propTypes = { | |||
| children: PropTypes.node, | |||
| filters: PropTypes.any, | |||
| }; | |||
| export default FilterCard; | |||
| @@ -24,11 +24,7 @@ const FilterCheckboxDropdown = (props) => { | |||
| useEffect(() => { | |||
| setDataToShow([...data]); | |||
| }, []); | |||
| useEffect(() => { | |||
| console.log("props.filters: ", props.filters); | |||
| }, [props.filters]) | |||
| }, [data]); | |||
| useEffect(() => { | |||
| if (toSearch.length > 0) { | |||
| setDataToShow( | |||
| @@ -38,7 +34,6 @@ const FilterCheckboxDropdown = (props) => { | |||
| ); | |||
| } else { | |||
| setDataToShow([...data]); | |||
| } | |||
| }, [toSearch]); | |||
| @@ -46,12 +41,10 @@ const FilterCheckboxDropdown = (props) => { | |||
| if (props.oneValueAllowed) { | |||
| props.setItemsSelected[item.id]; | |||
| } else { | |||
| if (props.filters.includes(item.id)) { | |||
| props.setItemsSelected((itemsSelected) => [ | |||
| ...itemsSelected.filter((p) => p !== item.id), | |||
| ]); | |||
| if (props.filters.includes(item)) { | |||
| props.setItemsSelected([...props.filters.filter((p) => p !== item)]); | |||
| } else { | |||
| props.setItemsSelected((itemsSelected) => [...itemsSelected, item.id]); | |||
| props.setItemsSelected([...props.filters, item]); | |||
| } | |||
| } | |||
| }; | |||
| @@ -80,14 +73,19 @@ const FilterCheckboxDropdown = (props) => { | |||
| fullWidth | |||
| setIsOpened={setIsOpened} | |||
| toggleIconStyles={{ | |||
| backgroundColor: isOpened ? "white" : selectedTheme.primaryIconBackgroundColor, | |||
| backgroundColor: isOpened | |||
| ? "white" | |||
| : selectedTheme.primaryIconBackgroundColor, | |||
| }} | |||
| headerOptions={ | |||
| <React.Fragment> | |||
| <SelectedItemsContainer> | |||
| {props.filters.map((item) => ( | |||
| <SelectedItem key={item} onClick={() => handleDelete(item)}> | |||
| {data.find((p) => p.id === item).string} | |||
| <SelectedItem key={item.city} onClick={() => handleDelete(item)}> | |||
| { | |||
| data.find((p) => p.city.toString() === item.city.toString()) | |||
| ?.city | |||
| } | |||
| <Close style={{ position: "relative", top: "3px" }} /> | |||
| </SelectedItem> | |||
| ))} | |||
| @@ -118,12 +116,12 @@ const FilterCheckboxDropdown = (props) => { | |||
| } | |||
| > | |||
| {dataToShow.map((item) => ( | |||
| <DropdownItem key={item.id}> | |||
| <DropdownItem key={item.city}> | |||
| <CheckBox | |||
| leftText={item.string} | |||
| rightText={item.numberOfProducts} | |||
| value={item.id} | |||
| checked={props.filters.includes(item.id)} | |||
| leftText={item.city} | |||
| rightText={item.offerCount} | |||
| value={item} | |||
| checked={props.filters.includes(item)} | |||
| onChange={() => handleChange(item)} | |||
| fullWidth | |||
| /> | |||
| @@ -95,7 +95,7 @@ const FilterRadioDropdown = (props) => { | |||
| > | |||
| <RadioGroup> | |||
| {props.firstOption && ( | |||
| <DropdownItem key={0}> | |||
| <DropdownItem> | |||
| <RadioButton | |||
| value={props.firstOption.value} | |||
| label={props.firstOption.label} | |||
| @@ -107,13 +107,16 @@ const FilterRadioDropdown = (props) => { | |||
| </DropdownItem> | |||
| )} | |||
| {dataToShow.map((item) => { | |||
| console.log("item: ", item); | |||
| {/* console.log("item: ", item); */} | |||
| return ( | |||
| <DropdownItem key={item.name} onClick={() => props.setSelected(item)}> | |||
| <DropdownItem | |||
| key={item.name} | |||
| onClick={() => props.setSelected(item)} | |||
| > | |||
| <RadioButton | |||
| value={item} | |||
| label={item.name ? item.name : item} | |||
| // number={item.numberOfProducts} | |||
| number={item.offerCount} | |||
| fullWidth | |||
| checked={ | |||
| JSON.stringify(props.selected) === JSON.stringify(item) | |||
| @@ -137,7 +140,7 @@ FilterRadioDropdown.propTypes = { | |||
| fullWidth: PropTypes.bool, | |||
| searchPlaceholder: PropTypes.string, | |||
| setSelected: PropTypes.func, | |||
| selected: PropTypes.number, | |||
| selected: PropTypes.any, | |||
| firstOption: PropTypes.any, | |||
| disabled: PropTypes.bool, | |||
| open: PropTypes.bool, | |||
| @@ -17,12 +17,10 @@ import { | |||
| OfferImage, | |||
| OfferInfo, | |||
| OfferLocation, | |||
| OfferPackage, | |||
| OfferTitle, | |||
| OfferViews, | |||
| } from "./OfferCard.styled"; | |||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as Quantity } from "../../../assets/images/svg/quantity.svg"; | |||
| import { ReactComponent as Eye } from "../../../assets/images/svg/eye-striked.svg"; | |||
| import { ReactComponent as Message } from "../../../assets/images/svg/mail.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| @@ -44,17 +42,11 @@ const OfferCard = (props) => { | |||
| </DetailIcon> | |||
| <DetailText>{props.offer.category.name}</DetailText> | |||
| </OfferCategory> | |||
| <OfferPackage> | |||
| <DetailIcon color="black" component="span" size="16px"> | |||
| <Quantity width={"12px"} height={"12px"} /> | |||
| </DetailIcon> | |||
| <DetailText>{props.offer.quantity} pakovanja</DetailText> | |||
| </OfferPackage> | |||
| <OfferViews> | |||
| <DetailIcon color="black" component="span" size="16px"> | |||
| <Eye width={"12px"} height={"11px"} /> | |||
| </DetailIcon> | |||
| <DetailText>{props.offer.views.viewers.length} pregleda</DetailText> | |||
| <DetailText>{props.offer.views.viewers.length}</DetailText> | |||
| </OfferViews> | |||
| </OfferDetails> | |||
| </OfferInfo> | |||
| @@ -55,7 +55,7 @@ CheckBox.propTypes = { | |||
| rightText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | |||
| maxWidth: PropTypes.string, | |||
| checked: PropTypes.bool, | |||
| value: PropTypes.number, | |||
| value: PropTypes.any, | |||
| onChange: PropTypes.func, | |||
| containerStyle: PropTypes.any, | |||
| checkBoxStyle: PropTypes.any, | |||
| @@ -11,7 +11,7 @@ export const Label = (props) => { | |||
| className={props.className} | |||
| > | |||
| <LeftLabel style={props.leftTextStyle}>{props.leftText}</LeftLabel> | |||
| {props.rightText && <RightLabel>{props.rightText}</RightLabel>} | |||
| {props.rightText !== null ? <RightLabel>{props.rightText}</RightLabel> : <></>} | |||
| </LabelContainer> | |||
| ); | |||
| }; | |||
| @@ -1,10 +1,10 @@ | |||
| import React, { useEffect, useState } from "react"; | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| HeaderButton, | |||
| HeaderButtons, | |||
| HeaderContainer, | |||
| HeaderLocation, | |||
| // HeaderLocation, | |||
| HeaderOptions, | |||
| HeaderSelect, | |||
| IconStyled, | |||
| @@ -13,11 +13,11 @@ import { ReactComponent as GridSquare } from "../../../assets/images/svg/offer-g | |||
| import { ReactComponent as GridLine } from "../../../assets/images/svg/offer-grid-line.svg"; | |||
| import { ReactComponent as Down } from "../../../assets/images/svg/down-arrow.svg"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { useSelector } from "react-redux"; | |||
| import { selectFilters } from "../../../store/selectors/filtersSelectors"; | |||
| import Mockupdata from "../../Cards/FilterCard/Mockupdata"; | |||
| // import { useSelector } from "react-redux"; | |||
| // import { selectFilters } from "../../../store/selectors/filtersSelectors"; | |||
| // import Mockupdata from "../../Cards/FilterCard/Mockupdata"; | |||
| import Option from "../../Select/Option/Option"; | |||
| import { useHistory, useLocation, useRouteMatch } from "react-router-dom"; | |||
| // import { useHistory, useLocation, useRouteMatch } from "react-router-dom"; | |||
| import { sortEnum } from "../../../enums/sortEnum"; | |||
| const DownArrow = (props) => ( | |||
| @@ -27,55 +27,53 @@ const DownArrow = (props) => ( | |||
| ); | |||
| const Header = (props) => { | |||
| const [categoryString, setCategoryString] = useState(""); | |||
| const [filtersString, setFiltersString] = useState(""); | |||
| const { category, cities } = useSelector(selectFilters); | |||
| const history = useHistory(); | |||
| const location = useLocation(); | |||
| const routeMatch = useRouteMatch(); | |||
| // const [categoryString, setCategoryString] = useState(""); | |||
| // const [filtersString, setFiltersString] = useState(""); | |||
| // const { category, cities } = useSelector(selectFilters); | |||
| // const history = useHistory(); | |||
| // const location = useLocation(); | |||
| // const routeMatch = useRouteMatch(); | |||
| const filters = props.filters; | |||
| useEffect(() => { | |||
| let categorystring = ""; | |||
| if (category) { | |||
| categorystring = Mockupdata[1].find( | |||
| (item) => item.id === category | |||
| ).string; | |||
| } else { | |||
| categorystring = "Sve kategorije"; | |||
| } | |||
| let filtersstring = " | "; | |||
| if (cities) { | |||
| cities.forEach((item) => { | |||
| filtersstring = filtersstring.concat( | |||
| Mockupdata[0].find((p) => p.id === item).string + ", " | |||
| ); | |||
| }); | |||
| filtersstring = filtersstring.substring(0, filtersstring.length - 2); | |||
| } | |||
| console.log("categorysstring: ", categorystring); | |||
| console.log(filtersstring); | |||
| setCategoryString(categorystring); | |||
| setFiltersString(filtersstring); | |||
| }, [category, cities]); | |||
| // useEffect(() => { | |||
| // let categorystring = ""; | |||
| // if (category) { | |||
| // categorystring = Mockupdata[1].find( | |||
| // (item) => item.id === category | |||
| // ).string; | |||
| // } else { | |||
| // categorystring = "Sve kategorije"; | |||
| // } | |||
| // let filtersstring = " | "; | |||
| // if (cities) { | |||
| // cities.forEach((item) => { | |||
| // filtersstring = filtersstring.concat( | |||
| // Mockupdata[0].find((p) => p.id === item).string + ", " | |||
| // ); | |||
| // }); | |||
| // filtersstring = filtersstring.substring(0, filtersstring.length - 2); | |||
| // } | |||
| // console.log("categorysstring: ", categorystring); | |||
| // console.log(filtersstring); | |||
| // setCategoryString(categorystring); | |||
| // setFiltersString(filtersstring); | |||
| // }, [category, cities]); | |||
| const handleChangeSelect = (value) => { | |||
| const handleChangeSelect = (event) => { | |||
| let chosenOption; | |||
| for (const sortOption in sortEnum) { | |||
| console.log(sortEnum[sortOption]) | |||
| if (sortEnum[sortOption].value === value) { | |||
| // console.log(sortEnum[sortOption]) | |||
| if (sortEnum[sortOption].value === event.target.value) { | |||
| chosenOption = sortEnum[sortOption]; | |||
| // console.log(chosenOption) | |||
| filters.setSelectedSortOption(chosenOption); | |||
| } | |||
| } | |||
| console.log(location); | |||
| console.log(history); | |||
| console.log(chosenOption); | |||
| console.log(routeMatch) | |||
| } | |||
| }; | |||
| return ( | |||
| <HeaderContainer> | |||
| <HeaderLocation>{categoryString + filtersString} </HeaderLocation> | |||
| {/* <HeaderLocation>{categoryString + filtersString} </HeaderLocation> */} | |||
| <HeaderOptions> | |||
| <HeaderButtons> | |||
| <HeaderButton | |||
| @@ -100,23 +98,27 @@ const Header = (props) => { | |||
| </HeaderButton> | |||
| </HeaderButtons> | |||
| <HeaderSelect | |||
| defaultValue={0} | |||
| defaultValue={filters.selectedSortOption ? filters.selectedSortOption.value : 0} | |||
| IconComponent={DownArrow} | |||
| width="209px" | |||
| height="34px" | |||
| onChange={handleChangeSelect} | |||
| > | |||
| {Object.keys(sortEnum).map((property) => { | |||
| console.log(sortEnum[property]) | |||
| console.log(sortEnum[property]); | |||
| console.log(filters.selectedSortOption) | |||
| return ( | |||
| <Option | |||
| value={sortEnum[property].value} | |||
| key={sortEnum[property].value} | |||
| style={{ display: sortEnum[property].value === 0 ? "none" : "flex" }} | |||
| > | |||
| {sortEnum[property].mainText} | |||
| </Option> | |||
| )})} | |||
| <Option | |||
| value={sortEnum[property].value} | |||
| key={sortEnum[property].value} | |||
| style={{ | |||
| display: sortEnum[property].value === 0 ? "none" : "flex", | |||
| }} | |||
| > | |||
| {sortEnum[property].mainText} | |||
| </Option> | |||
| ); | |||
| })} | |||
| </HeaderSelect> | |||
| </HeaderOptions> | |||
| </HeaderContainer> | |||
| @@ -127,7 +129,7 @@ Header.propTypes = { | |||
| children: PropTypes.node, | |||
| setIsGrid: PropTypes.func, | |||
| isGrid: PropTypes.bool, | |||
| filters: PropTypes.array, | |||
| filters: PropTypes.any, | |||
| category: PropTypes.string, | |||
| }; | |||
| Header.defaultProps = { | |||
| @@ -1,39 +1,17 @@ | |||
| import React, { useEffect, useState } from "react"; | |||
| import React, { useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { MarketPlaceContainer } from "./MarketPlace.styled"; | |||
| import Header from "./Header/Header"; | |||
| import Offers from "./Offers/Offers"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { fetchCategories } from "../../store/actions/categories/categoriesActions"; | |||
| import { fetchLocations } from "../../store/actions/locations/locationsActions"; | |||
| import { selectSubcategories } from "../../store/selectors/categoriesSelectors"; | |||
| import useFilters from "../../hooks/useFilters"; | |||
| const MarketPlace = () => { | |||
| const [isGrid, setIsGrid] = useState(false); | |||
| const dispatch = useDispatch(); | |||
| const categories = useSelector(selectSubcategories("Automobili")); | |||
| useEffect(() => { | |||
| dispatch(fetchCategories()); | |||
| dispatch(fetchLocations()); | |||
| }, []); | |||
| useEffect(() => { | |||
| let newSubcategories = []; | |||
| if (categories) { | |||
| for (let i = 0; i < categories.length; i++) { | |||
| let subcategoryString = ""; | |||
| Object.keys(categories[i]).forEach(item => { | |||
| subcategoryString += categories[i][item] | |||
| }) | |||
| newSubcategories.push(subcategoryString) | |||
| } | |||
| } | |||
| console.log("selektor: ", newSubcategories); | |||
| }, [categories]); | |||
| const filters = useFilters(); | |||
| return ( | |||
| <MarketPlaceContainer> | |||
| <Header isGrid={isGrid} setIsGrid={setIsGrid} /> | |||
| <Header isGrid={isGrid} setIsGrid={setIsGrid} filters={filters} /> | |||
| <Offers isGrid={isGrid} /> | |||
| </MarketPlaceContainer> | |||
| ); | |||
| @@ -1,4 +1,4 @@ | |||
| import React, { useEffect } from "react"; | |||
| import React, { useEffect, useRef} from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { OffersContainer } from "./Offers.styled"; | |||
| import OfferCard from "../../Cards/OfferCard/OfferCard"; | |||
| @@ -11,6 +11,20 @@ import { selectOffers } from "../../../store/selectors/offersSelectors"; | |||
| const Offers = (props) => { | |||
| const offersRef = useRef(null); | |||
| useEffect(() => { | |||
| const listener = () => { | |||
| // console.log(window.scrollY); | |||
| // console.log(window.document.body.offsetHeight); | |||
| if (window.scrollY > window.document.body.offsetHeight * 0.7) { | |||
| console.log('sad treba') | |||
| } | |||
| } | |||
| window.addEventListener('scroll', listener) | |||
| return () => window.removeEventListener('scroll', listener); | |||
| }, []) | |||
| // Market place nije zavrsen | |||
| // Koriste se Mockup podaci | |||
| const dispatch = useDispatch(); | |||
| @@ -18,12 +32,14 @@ const Offers = (props) => { | |||
| useEffect(() => { | |||
| dispatch(fetchOffers()); | |||
| }, []) | |||
| }, []); | |||
| return ( | |||
| <OffersContainer> | |||
| <OffersContainer ref={offersRef} onScroll={() => console.log('proba')} onClick={() => console.log(offersRef)}> | |||
| {offers.map((item) => { | |||
| return <OfferCard key={item._id} offer={item} halfwidth={props.isGrid} />; | |||
| return ( | |||
| <OfferCard key={item._id} offer={item} halfwidth={props.isGrid} /> | |||
| ); | |||
| })} | |||
| </OffersContainer> | |||
| ); | |||
| @@ -37,7 +37,7 @@ const RadioButton = (props) => { | |||
| RadioButton.propTypes = { | |||
| children: PropTypes.node, | |||
| value: PropTypes.number, | |||
| value: PropTypes.any, | |||
| label: PropTypes.string, | |||
| number: PropTypes.number, | |||
| fullWidth: PropTypes.bool, | |||
| @@ -5,7 +5,7 @@ import { OptionIcon, OptionStyled } from './Option.styled' | |||
| const Option = props => { | |||
| console.log(props) | |||
| return ( | |||
| <OptionStyled {...props}> | |||
| <OptionStyled {...props} value={props.value} > | |||
| {props.startIcon ? ( | |||
| <OptionIcon color={props.color}> | |||
| {props.startIcon} | |||
| @@ -22,6 +22,11 @@ Option.propTypes = { | |||
| children: PropTypes.node, | |||
| color: PropTypes.any, | |||
| startIcon: PropTypes.any, | |||
| value: PropTypes.any, | |||
| // selected: PropTypes.bool, | |||
| } | |||
| Option.defaultProps = { | |||
| // selected: true | |||
| } | |||
| export default Option | |||
| @@ -1,18 +1,22 @@ | |||
| export const sortEnum = { | |||
| INITIAL: { | |||
| value: 0, | |||
| mainText: "Sortiraj po" | |||
| mainText: "Sortiraj po", | |||
| queryString: "" | |||
| }, | |||
| POPULAR: { | |||
| value: 1, | |||
| mainText: "Najpopularnije" | |||
| mainText: "Najpopularnije", | |||
| queryString: "popular" | |||
| }, | |||
| NEW: { | |||
| value: 2, | |||
| mainText: "Najnovije" | |||
| mainText: "Najnovije", | |||
| queryString: "newest" | |||
| }, | |||
| OLD: { | |||
| value: 3, | |||
| mainText: "Najstarije" | |||
| mainText: "Najstarije", | |||
| queryString: "oldest" | |||
| } | |||
| } | |||
| @@ -1,69 +1,188 @@ | |||
| import { useEffect, useState } from "react"; | |||
| import { useDispatch } from "react-redux"; | |||
| import { useSelector } from "react-redux"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { sortEnum } from "../enums/sortEnum"; | |||
| import { fetchCategories } from "../store/actions/categories/categoriesActions"; | |||
| import { | |||
| setFilteredCategory, | |||
| setFilteredLocations, | |||
| setFilteredSortOption, | |||
| setFilteredSubcategory, | |||
| } from "../store/actions/filters/filtersActions"; | |||
| import { fetchLocations } from "../store/actions/locations/locationsActions"; | |||
| import { | |||
| selectCategories, | |||
| selectSubcategories, | |||
| } from "../store/selectors/categoriesSelectors"; | |||
| // import qs from "query-string"; | |||
| import { | |||
| selectSelectedCategory, | |||
| selectSelectedLocations, | |||
| selectSelectedSortOption, | |||
| selectSelectedSubcategory, | |||
| } from "../store/selectors/filtersSelectors"; | |||
| import qs from "query-string"; | |||
| import { selectLocations } from "../store/selectors/locationsSelectors"; | |||
| import { fetchOffers } from "../store/actions/offers/offersActions"; | |||
| import { HOME_PAGE } from "../constants/pages"; | |||
| const useFilters = () => { | |||
| const [selectedCategory, setSelectedCategory] = useState(); | |||
| const [selectedSubcategory, setSelectedSubcategory] = useState(); | |||
| const [selectedLocations, setSelectedLocations] = useState([]); | |||
| const [selectedSortOption, setSelectedSortOption] = useState({}); | |||
| const [queryString, setQueryString] = useState(); | |||
| const selectedCategory = useSelector(selectSelectedCategory); | |||
| const selectedSubcategory = useSelector(selectSelectedSubcategory); | |||
| const selectedLocations = useSelector(selectSelectedLocations); | |||
| const selectedSortOption = useSelector(selectSelectedSortOption); | |||
| const [loaded, setLoadedStatus] = useState(false); | |||
| const history = useHistory(); | |||
| const categories = useSelector(selectCategories); | |||
| const subcategories = useSelector( | |||
| selectSubcategories(selectedCategory?.name) | |||
| ); | |||
| const locations = useSelector(selectLocations); | |||
| const sortOptions = sortEnum; | |||
| const dispatch = useDispatch(); | |||
| useEffect(() => { | |||
| dispatch(fetchCategories()); | |||
| dispatch(fetchLocations()); | |||
| }, []); | |||
| if (!loaded) { | |||
| dispatch(fetchCategories()); | |||
| dispatch(fetchLocations()); | |||
| setLoadedStatus(true); | |||
| } | |||
| }, [categories, locations]); | |||
| useEffect(() => { | |||
| console.log("selectedCategory changed: ", selectedCategory); | |||
| }, [selectedCategory]) | |||
| // useEffect(() => { | |||
| // if (categories && locations) { | |||
| // const queryString = history.location.search.substring(1); | |||
| // const queryObject = qs.parse(queryString); | |||
| // let category; | |||
| // if (queryObject.category) { | |||
| // category = categories.find( | |||
| // (item) => item.mainText === queryObject.category.toString() | |||
| // ); | |||
| // setSelectedCategory(category); | |||
| // } | |||
| // if (queryObject.subcategory) { | |||
| // setSelectedSubcategory( | |||
| // category.subcategories.find( | |||
| // (item) => item.mainText === queryObject.subcategory.toString() | |||
| // ).id | |||
| // ); | |||
| // } | |||
| // if (queryObject.city) { | |||
| // let filters = []; | |||
| // if (Array.isArray(queryObject.city)) { | |||
| // queryObject.city.forEach((item) => { | |||
| // filters.push(Mockupdata[0].find((p) => p.string === item).id); | |||
| // }); | |||
| // } else { | |||
| // filters.push( | |||
| // Mockupdata[0].find((p) => p.string === queryObject.city).id | |||
| // ); | |||
| // } | |||
| // setAppliedFilters([...filters]); | |||
| // } | |||
| // } | |||
| // }, [categories, locations]); | |||
| if (categories && locations) { | |||
| const queryString = history.location.search.substring(1); | |||
| const queryObject = qs.parse(queryString); | |||
| let category; | |||
| if (queryObject.category) { | |||
| category = categories.find( | |||
| (item) => item.name === queryObject.category.toString() | |||
| ); | |||
| setSelectedCategory(category); | |||
| } | |||
| if (queryObject.subcategory) { | |||
| setSelectedSubcategory( | |||
| category.subcategories.find( | |||
| (item) => item.toString() === queryObject.subcategory.toString() | |||
| ) | |||
| ); | |||
| } | |||
| if (queryObject.location) { | |||
| let locationsToPush = []; | |||
| if (Array.isArray(queryObject.location)) { | |||
| queryObject.location.forEach((item) => { | |||
| locationsToPush.push(locations.find((p) => p.city === item)); | |||
| }); | |||
| } else { | |||
| locationsToPush.push( | |||
| locations.find((p) => p.city === queryObject.location) | |||
| ); | |||
| } | |||
| setSelectedLocations([...locationsToPush]); | |||
| } | |||
| // For future changes if needed | |||
| if (queryObject._des_date || queryObject._des_popular) { | |||
| if (queryObject._des_date === false) { | |||
| setSelectedSortOption(sortOptions.OLD); | |||
| } | |||
| if (queryObject._des_date === true) { | |||
| setSelectedSortOption(sortOptions.NEW); | |||
| } | |||
| if (queryObject._des_popular === true) { | |||
| setSelectedSortOption(sortOptions.POPULAR); | |||
| } | |||
| } | |||
| // if (queryObject.sortBy) { | |||
| // if (queryObject.sortBy === "oldest") { | |||
| // setSelectedSortOption(sortOptions.OLD); | |||
| // } | |||
| // if (queryObject.sortBy === "newest") { | |||
| // setSelectedSortOption(sortOptions.NEW); | |||
| // } | |||
| // if (queryObject.sortBy === "popular") { | |||
| // setSelectedSortOption(sortOptions.POPULAR); | |||
| // } | |||
| // } | |||
| } | |||
| }, [history.location.search]); | |||
| const clearFilters = () => { | |||
| setSelectedLocations([]); | |||
| setSelectedSubcategory(); | |||
| setSelectedCategory(); | |||
| // history.push({ | |||
| // pathname: HOME_PAGE, | |||
| // search: "", | |||
| // }); | |||
| // window.scrollTo({ | |||
| // top: 0, | |||
| // behavior: "smooth", | |||
| // }); | |||
| }; | |||
| useEffect(() => { | |||
| console.log("subcategories: ", subcategories); | |||
| }, [subcategories]); | |||
| let qsArray = []; | |||
| if (selectedCategory && selectedCategory?._id !== 0) { | |||
| qsArray.push("category=" + encodeURIComponent(selectedCategory.name)); | |||
| } | |||
| if (selectedSubcategory && selectedSubcategory?._id !== 0) { | |||
| qsArray.push("subcategory=" + encodeURIComponent(selectedSubcategory)); | |||
| } | |||
| if (selectedLocations && selectedLocations?.length > 0) { | |||
| selectedLocations.forEach((location) => { | |||
| qsArray.push("location=" + encodeURIComponent(location.city)); | |||
| }); | |||
| } | |||
| if (selectedSortOption) { | |||
| let _des_date = null; | |||
| let _des_popular = null; | |||
| if (selectedSortOption === sortOptions.NEW) { | |||
| _des_date = true; | |||
| } | |||
| if (selectedSortOption === sortOptions.OLD) { | |||
| _des_date = false; | |||
| } | |||
| if (selectedSortOption === sortOptions.POPULAR) { | |||
| _des_popular = true; | |||
| } | |||
| if (_des_date !== null) | |||
| qsArray.push("_des_date=" + encodeURIComponent(_des_date)); | |||
| if (_des_popular !== null) | |||
| qsArray.push("_des_popular=" + encodeURIComponent(_des_popular)); | |||
| } | |||
| let qsStringFromArray = "?" + qsArray.join("&"); | |||
| console.log(qsStringFromArray); | |||
| setQueryString(qsStringFromArray); | |||
| }, [ | |||
| selectedCategory, | |||
| selectedLocations, | |||
| selectedSortOption, | |||
| selectedSubcategory, | |||
| ]); | |||
| const applyFilters = () => { | |||
| dispatch(fetchOffers(queryString)); | |||
| history.push({ | |||
| pathname: HOME_PAGE, | |||
| search: queryString, | |||
| }); | |||
| window.scrollTo({ | |||
| top: 0, | |||
| behavior: "smooth", | |||
| }); | |||
| }; | |||
| const setSelectedCategory = (payload) => { | |||
| dispatch(setFilteredCategory(payload)); | |||
| }; | |||
| const setSelectedSubcategory = (payload) => { | |||
| dispatch(setFilteredSubcategory(payload)); | |||
| }; | |||
| const setSelectedLocations = (payload) => { | |||
| dispatch(setFilteredLocations(payload)); | |||
| }; | |||
| const setSelectedSortOption = (payload) => { | |||
| dispatch(setFilteredSortOption(payload)); | |||
| }; | |||
| return { | |||
| selectedCategory, | |||
| setSelectedCategory, | |||
| @@ -76,6 +195,10 @@ const useFilters = () => { | |||
| categories, | |||
| subcategories, | |||
| locations, | |||
| sortOptions, | |||
| queryString, | |||
| applyFilters, | |||
| clearFilters, | |||
| }; | |||
| }; | |||
| @@ -1,64 +1,64 @@ | |||
| import React, { useEffect } from "react"; | |||
| import React from "react"; | |||
| import Navbar from "../../components/MUI/NavbarComponent"; | |||
| // import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | |||
| import { HomePageContainer } from "./HomePage.styled"; | |||
| // import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||
| // import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||
| import { useDispatch } from "react-redux"; | |||
| // import { logoutUser } from "../../store/actions/login/loginActions"; | |||
| import Mockupdata from "../../components/Cards/FilterCard/Mockupdata"; | |||
| import qs from "query-string"; | |||
| import { useHistory } from "react-router-dom"; | |||
| import { setFilters } from "../../store/actions/filters/filtersActions"; | |||
| // import { useDispatch } from "react-redux"; | |||
| // // import { logoutUser } from "../../store/actions/login/loginActions"; | |||
| // import Mockupdata from "../../components/Cards/FilterCard/Mockupdata"; | |||
| // import qs from "query-string"; | |||
| // import { useHistory } from "react-router-dom"; | |||
| // import { setFilters } from "../../store/actions/filters/filtersActions"; | |||
| // import ProfileLayout from "../../layouts/ProfileLayout/ProfileLayout"; | |||
| import FilterCard from "../../components/Cards/FilterCard/FilterCard"; | |||
| import MainLayout from "../../layouts/MainLayout/MainLayout"; | |||
| import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||
| const HomePage = () => { | |||
| const dispatch = useDispatch(); | |||
| // const dispatch = useDispatch(); | |||
| const history = useHistory(); | |||
| useEffect(() => { | |||
| let category = null, subcategory = null, cities = [], _des_date = false, _des_popular = false, page, size; | |||
| const queryString = history.location.search.substring(1); | |||
| const queryObject = qs.parse(queryString); | |||
| // const history = useHistory(); | |||
| // useEffect(() => { | |||
| // let category = null, subcategory = null, cities = [], _des_date = false, _des_popular = false, page, size; | |||
| // const queryString = history.location.search.substring(1); | |||
| // const queryObject = qs.parse(queryString); | |||
| if (queryObject.category) { | |||
| category = Mockupdata[1].find( | |||
| (item) => item.string === queryObject.category.toString() | |||
| ).id; | |||
| } | |||
| if (queryObject.subcategory) { | |||
| subcategory = Mockupdata[1].find( | |||
| (item) => item.string === queryObject.subcategory.toString() | |||
| ).id; | |||
| } | |||
| if (queryObject.city) { | |||
| if (Array.isArray(queryObject.city)) { | |||
| queryObject.city.forEach((item) => { | |||
| cities.push(Mockupdata[0].find((p) => p.string === item).id); | |||
| }); | |||
| } else { | |||
| cities.push( | |||
| Mockupdata[0].find((p) => p.string === queryObject.city).id | |||
| ); | |||
| } | |||
| } | |||
| if (queryObject.sortBy) { | |||
| if (queryObject.sortBy === "dateAsc") _des_date = false; | |||
| if (queryObject.sortBy === "dateDesc") _des_date = true; | |||
| if (queryObject.sortBy === "popular") _des_popular = true; | |||
| } | |||
| if (queryObject.page) { | |||
| page = queryObject.page; | |||
| } | |||
| if (queryObject.size) { | |||
| size = queryObject.size; | |||
| } | |||
| // if (queryObject.category) { | |||
| // category = Mockupdata[1].find( | |||
| // (item) => item.string === queryObject.category.toString() | |||
| // ).id; | |||
| // } | |||
| // if (queryObject.subcategory) { | |||
| // subcategory = Mockupdata[1].find( | |||
| // (item) => item.string === queryObject.subcategory.toString() | |||
| // ).id; | |||
| // } | |||
| // if (queryObject.city) { | |||
| // if (Array.isArray(queryObject.city)) { | |||
| // queryObject.city.forEach((item) => { | |||
| // cities.push(Mockupdata[0].find((p) => p.string === item).id); | |||
| // }); | |||
| // } else { | |||
| // cities.push( | |||
| // Mockupdata[0].find((p) => p.string === queryObject.city).id | |||
| // ); | |||
| // } | |||
| // } | |||
| // if (queryObject.sortBy) { | |||
| // if (queryObject.sortBy === "dateAsc") _des_date = false; | |||
| // if (queryObject.sortBy === "dateDesc") _des_date = true; | |||
| // if (queryObject.sortBy === "popular") _des_popular = true; | |||
| // } | |||
| // if (queryObject.page) { | |||
| // page = queryObject.page; | |||
| // } | |||
| // if (queryObject.size) { | |||
| // size = queryObject.size; | |||
| // } | |||
| dispatch(setFilters({ category, subcategory, cities, _des_date, _des_popular, page, size })); | |||
| }, [history.location.search]); | |||
| // dispatch(setFilters({ category, subcategory, cities, _des_date, _des_popular, page, size })); | |||
| // }, [history.location.search]); | |||
| return ( | |||
| <HomePageContainer> | |||
| @@ -3,7 +3,7 @@ import queryString from "qs"; | |||
| const request = axios.create({ | |||
| // baseURL: "http://192.168.88.150:3001/", | |||
| baseURL: "http://192.168.88.175:3005/", | |||
| baseURL: "http://192.168.88.176:3001/", | |||
| headers: { | |||
| "Content-Type": "application/json", | |||
| }, | |||
| @@ -13,7 +13,7 @@ const request = axios.create({ | |||
| }); | |||
| export const getRequest = (url, params = null, options = null) => { | |||
| console.log('poziv') | |||
| console.log('url: ', url); | |||
| return request.get(url, { params, ...options }); | |||
| } | |||
| @@ -1,8 +1,9 @@ | |||
| import { getRequest, postRequest } from "." | |||
| import apiEndpoints from "./apiEndpoints" | |||
| export const attemptFetchOffers = () => { | |||
| return getRequest(apiEndpoints.offers.getOffers) | |||
| export const attemptFetchOffers = (payload) => { | |||
| if (payload) return getRequest(apiEndpoints.offers.getOffers + payload + "&size=10") | |||
| return getRequest(apiEndpoints.offers.getOffers + "?size=10") | |||
| } | |||
| export const attemptAddOffer = (payload) => { | |||
| return postRequest(apiEndpoints.offers.addOffer, payload) | |||
| @@ -5,4 +5,5 @@ export const SET_FILTERS = createSetType(FILTERS_SCOPE); | |||
| export const CLEAR_FILTERS = createClearType(FILTERS_SCOPE); | |||
| export const SET_CATEGORY = "FILTERS_SET_CATEGORY"; | |||
| export const SET_SUBCATEGORY = "FILTERS_SET_SUBCATEGORY"; | |||
| export const SET_CITIES = "FILTERS_SET_CITIES"; | |||
| export const SET_LOCATIONS = "FILTERS_SET_LOCATIONS"; | |||
| export const SET_SORT_OPTION = "FILTERS_SET_SORT_OPTION"; | |||
| @@ -1,4 +1,4 @@ | |||
| import { CLEAR_FILTERS, SET_CATEGORY, SET_CITIES, SET_FILTERS, SET_SUBCATEGORY } from "./filtersActionConstants"; | |||
| import { CLEAR_FILTERS, SET_CATEGORY, SET_FILTERS, SET_LOCATIONS, SET_SORT_OPTION, SET_SUBCATEGORY } from "./filtersActionConstants"; | |||
| export const setFilters = (payload) => ({ | |||
| type: SET_FILTERS, | |||
| @@ -7,15 +7,19 @@ export const setFilters = (payload) => ({ | |||
| export const clearFilters = () => ({ | |||
| type: CLEAR_FILTERS | |||
| }) | |||
| export const setCategory = (payload) => ({ | |||
| export const setFilteredCategory = (payload) => ({ | |||
| type: SET_CATEGORY, | |||
| payload | |||
| }) | |||
| export const setSubcategory = (payload) => ({ | |||
| export const setFilteredSubcategory = (payload) => ({ | |||
| type: SET_SUBCATEGORY, | |||
| payload | |||
| }) | |||
| export const setCities = (payload) => ({ | |||
| type: SET_CITIES, | |||
| export const setFilteredLocations = (payload) => ({ | |||
| type: SET_LOCATIONS, | |||
| payload | |||
| }) | |||
| export const setFilteredSortOption = (payload) => ({ | |||
| type: SET_SORT_OPTION, | |||
| payload | |||
| }) | |||
| @@ -1,8 +1,9 @@ | |||
| import { | |||
| CLEAR_FILTERS, | |||
| SET_CATEGORY, | |||
| SET_CITIES, | |||
| SET_FILTERS, | |||
| SET_LOCATIONS, | |||
| SET_SORT_OPTION, | |||
| SET_SUBCATEGORY, | |||
| } from "../../actions/filters/filtersActionConstants"; | |||
| import createReducer from "../../utils/createReducer"; | |||
| @@ -11,7 +12,8 @@ const initialState = { | |||
| filters: { | |||
| category: null, | |||
| subcategory: null, | |||
| cities: [], | |||
| locations: [], | |||
| sortOption: null, | |||
| }, | |||
| }; | |||
| @@ -19,9 +21,10 @@ export default createReducer( | |||
| { | |||
| [SET_FILTERS]: setFilters, | |||
| [CLEAR_FILTERS]: clearFilters, | |||
| [SET_CATEGORY]: setCategory, | |||
| [SET_SUBCATEGORY]: setSubcategory, | |||
| [SET_CITIES]: setCities, | |||
| [SET_CATEGORY]: setFilteredCategory, | |||
| [SET_SUBCATEGORY]: setFilteredSubcategory, | |||
| [SET_LOCATIONS]: setFilteredLocations, | |||
| [SET_SORT_OPTION]: setFilteredSortOption, | |||
| }, | |||
| initialState | |||
| ); | |||
| @@ -37,7 +40,7 @@ function clearFilters() { | |||
| return initialState; | |||
| } | |||
| function setCategory(state, { payload }) { | |||
| function setFilteredCategory(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| filters: { | |||
| @@ -47,7 +50,7 @@ function setCategory(state, { payload }) { | |||
| }; | |||
| } | |||
| function setSubcategory(state, { payload }) { | |||
| function setFilteredSubcategory(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| filters: { | |||
| @@ -57,12 +60,21 @@ function setSubcategory(state, { payload }) { | |||
| }; | |||
| } | |||
| function setCities(state, { payload }) { | |||
| function setFilteredLocations(state, { payload }) { | |||
| return { | |||
| ...state, | |||
| filters: { | |||
| ...state.filters, | |||
| cities: payload, | |||
| locations: payload, | |||
| }, | |||
| }; | |||
| } | |||
| function setFilteredSortOption(state, {payload}) { | |||
| return { | |||
| ...state, | |||
| filters: { | |||
| ...state.filters, | |||
| sortOption: payload, | |||
| } | |||
| } | |||
| } | |||
| @@ -49,12 +49,17 @@ const locationsPersistConfig = { | |||
| storage: storage, | |||
| transform: [createFilter("locations", ["_id", "city"])], | |||
| }; | |||
| const filtersPersistConfig = { | |||
| key: "filters", | |||
| storage: storage, | |||
| transform: [createFilter("filters", ["category", "subcategory", "locations", "sortOption"])] | |||
| } | |||
| export default combineReducers({ | |||
| login: persistReducer(loginPersistConfig, loginReducer), | |||
| user: persistReducer(userPersistConfig, userReducer), | |||
| loading: loadingReducer, | |||
| filters: filtersReducer, | |||
| filters: persistReducer(filtersPersistConfig, filtersReducer), | |||
| randomData: persistReducer(randomDataPersistConfig, randomDataReducer), | |||
| offers: offersReducer, | |||
| categories: persistReducer(categoriesPersistConfig, categoriesReducer), | |||
| @@ -3,15 +3,24 @@ import { attemptAddOffer, attemptFetchOffers } from "../../request/offersRequest | |||
| import { OFFERS_FETCH, OFFER_ADD } from "../actions/offers/offersActionConstants"; | |||
| import { setOffers } from "../actions/offers/offersActions"; | |||
| function* fetchOffers() { | |||
| function* fetchOffers(payload) { | |||
| try { | |||
| const data = yield call(attemptFetchOffers); | |||
| console.log(payload); | |||
| const data = yield call(attemptFetchOffers, payload.payload); | |||
| console.log(data.data.items) | |||
| yield put(setOffers(data.data.items)) | |||
| } catch (e) { | |||
| console.log(e); | |||
| } | |||
| } | |||
| // function* fetchMoreOffers(payload) { | |||
| // try { | |||
| // const data = yield call(attemptFetchOffers,) | |||
| // } | |||
| // catch (e) { | |||
| // console.log(e); | |||
| // } | |||
| // } | |||
| function* createOffer(payload) { | |||
| try { | |||
| @@ -6,4 +6,19 @@ export const selectFilters = createSelector( | |||
| filtersSelector, | |||
| (state) => state.filters, | |||
| ); | |||
| export const selectSelectedCategory = createSelector( | |||
| filtersSelector, | |||
| (state => state.filters.category) | |||
| ) | |||
| export const selectSelectedSubcategory = createSelector( | |||
| filtersSelector, | |||
| (state) => state.filters.subcategory | |||
| ) | |||
| export const selectSelectedLocations = createSelector( | |||
| filtersSelector, | |||
| (state) => state.filters.locations | |||
| ) | |||
| export const selectSelectedSortOption = createSelector( | |||
| filtersSelector, | |||
| (state) => state.filters.sortOption | |||
| ) | |||