| "lodash": "^4.17.21", | "lodash": "^4.17.21", | ||||
| "lodash.isempty": "^4.4.0", | "lodash.isempty": "^4.4.0", | ||||
| "owasp-password-strength-test": "^1.3.0", | "owasp-password-strength-test": "^1.3.0", | ||||
| "query-string": "^7.1.1", | |||||
| "react": "^17.0.2", | "react": "^17.0.2", | ||||
| "react-dom": "^17.0.2", | "react-dom": "^17.0.2", | ||||
| "react-helmet-async": "^1.0.9", | "react-helmet-async": "^1.0.9", |
| <svg width="25" height="28" viewBox="0 0 25 28" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <g clip-path="url(#clip0_86_8377)"> | |||||
| <path d="M7.49117 6.3122L1.21472 7.6463L2.54882 13.9227L8.82527 12.5886L7.49117 6.3122Z" stroke="#9677BE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M17.3542 4.21577L11.0778 5.54987L12.4119 11.8263L18.6883 10.4922L17.3542 4.21577Z" stroke="#9677BE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M19.4506 14.0787L13.1742 15.4128L14.5083 21.6893L20.7847 20.3552L19.4506 14.0787Z" stroke="#9677BE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M9.5876 16.1752L3.31116 17.5093L4.64526 23.7857L10.9217 22.4516L9.5876 16.1752Z" stroke="#9677BE" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| </g> | |||||
| <defs> | |||||
| <clipPath id="clip0_86_8377"> | |||||
| <rect width="22" height="22" fill="white" transform="translate(-2.04688 5.52814) rotate(-12)"/> | |||||
| </clipPath> | |||||
| </defs> | |||||
| </svg> |
| <svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <path d="M9.16667 2.75H2.75V9.16667H9.16667V2.75Z" stroke="#4D4D4D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M19.2499 2.75H12.8333V9.16667H19.2499V2.75Z" stroke="#4D4D4D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M19.2499 12.8333H12.8333V19.25H19.2499V12.8333Z" stroke="#4D4D4D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| <path d="M9.16667 12.8333H2.75V19.25H9.16667V12.8333Z" stroke="#4D4D4D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> | |||||
| </svg> |
| <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <rect x="0.5" y="0.5" width="13" height="13" rx="6.5" fill="#64468B" stroke="#5A3984"/> | |||||
| </svg> |
| <svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg"> | |||||
| <rect x="0.5" y="0.5" width="13" height="13" rx="6.5" stroke="#5A3984"/> | |||||
| </svg> |
| import React from "react"; | |||||
| import React, { useEffect } from "react"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { | import { | ||||
| ContentContainer, | |||||
| FilterCardContainer, | FilterCardContainer, | ||||
| Footer, | Footer, | ||||
| Header, | Header, | ||||
| Title, | Title, | ||||
| } from "./FilterCard.styled"; | } from "./FilterCard.styled"; | ||||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | ||||
| 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 { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | ||||
| import Link from "../../Link/Link"; | import Link from "../../Link/Link"; | ||||
| import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | import { PrimaryButton } from "../../Buttons/PrimaryButton/PrimaryButton"; | ||||
| import FilterDropdown from "./FilterDropdown.js/FilterDropdown"; | |||||
| import FilterCheckboxDropdown from "./FilterDropdown/Checkbox/FilterCheckboxDropdown"; | |||||
| import Mockupdata from "./Mockupdata"; | 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"; | |||||
| const FilterCard = () => { | const FilterCard = () => { | ||||
| const [appliedFilters, setAppliedFilters] = useState([]); | |||||
| const [selectedCategory, setSelectedCategory] = useState(0); | |||||
| const [selectedSubcategory, setSelectedSubcategory] = useState(0); | |||||
| const history = useHistory(); | |||||
| const {t} = useTranslation(); | |||||
| 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 = []; | |||||
| queryObject.city.forEach((item) => { | |||||
| filters.push(Mockupdata[0].find((p) => p.string === item).id); | |||||
| }); | |||||
| setAppliedFilters([...filters]); | |||||
| } | |||||
| }, []); | |||||
| const handleFilters = () => { | |||||
| let queryObject = {}; | |||||
| if (selectedCategory !== 0) { | |||||
| queryObject = { | |||||
| category: Mockupdata[1].find( | |||||
| (item) => item.id.toString() === selectedCategory.toString() | |||||
| ).string, | |||||
| }; | |||||
| if (selectedSubcategory !== 0) { | |||||
| queryObject = { | |||||
| ...queryObject, | |||||
| subcategory: Mockupdata[1].find( | |||||
| (item) => item.id.toString() === selectedSubcategory.toString() | |||||
| ).string, | |||||
| }; | |||||
| } | |||||
| } | |||||
| if (appliedFilters.length > 0) { | |||||
| let arrayObject = []; | |||||
| appliedFilters.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, | |||||
| }); | |||||
| }; | |||||
| const clearFilters = () => { | |||||
| setAppliedFilters([]); | |||||
| setSelectedCategory(0); | |||||
| setSelectedSubcategory(0); | |||||
| }; | |||||
| return ( | return ( | ||||
| <FilterCardContainer> | <FilterCardContainer> | ||||
| <Header> | |||||
| <Title>Filteri</Title> | |||||
| <Link to="#" textsize={"12px"}> | |||||
| Ponisti filtere | |||||
| </Link> | |||||
| </Header> | |||||
| <ContentContainer> | |||||
| <Header> | |||||
| <Title>{t("filters.title")}</Title> | |||||
| <Link to="#" textsize={"12px"} onClick={clearFilters}> | |||||
| {t("filters.cancel")} | |||||
| </Link> | |||||
| </Header> | |||||
| <FilterRadioDropdown | |||||
| data={[...Mockupdata[1]]} | |||||
| icon={ | |||||
| selectedCategory && selectedCategory !== 0 ? ( | |||||
| <CategoryChosen /> | |||||
| ) : ( | |||||
| <Category /> | |||||
| ) | |||||
| } | |||||
| title={ | |||||
| selectedCategory && selectedCategory !== 0 | |||||
| ? Mockupdata[1].find( | |||||
| (item) => item.id.toString() === selectedCategory.toString() | |||||
| ).string | |||||
| : t("filters.categories.title") | |||||
| } | |||||
| searchPlaceholder={t("filters.categories.placeholder")} | |||||
| setSelected={setSelectedCategory} | |||||
| selected={selectedCategory} | |||||
| /> | |||||
| <FilterDropdown data={[]} icon={<Subcategory />} title="Podkategorija" /> | |||||
| <FilterRadioDropdown | |||||
| data={[...Mockupdata[1]]} | |||||
| icon={<Subcategory />} | |||||
| title={t("filters.subcategories.title")} | |||||
| searchPlaceholder={t("filters.subcategories.placeholder")} | |||||
| setSelected={setSelectedSubcategory} | |||||
| selected={selectedSubcategory} | |||||
| /> | |||||
| <FilterDropdown | |||||
| data={[...Mockupdata]} | |||||
| icon={<Location />} | |||||
| title="Lokacija" | |||||
| /> | |||||
| <FilterCheckboxDropdown | |||||
| searchPlaceholder={t("filters.location.placeholder")} | |||||
| data={[...Mockupdata[0]]} | |||||
| filters={appliedFilters} | |||||
| icon={<Location />} | |||||
| title={t("filters.location.title")} | |||||
| setItemsSelected={setAppliedFilters} | |||||
| /> | |||||
| </ContentContainer> | |||||
| <Footer> | <Footer> | ||||
| <PrimaryButton variant="outlined" fullWidth> | |||||
| PRIMENI FILTERE | |||||
| <PrimaryButton variant="outlined" fullWidth onClick={handleFilters}> | |||||
| {t("filters.usefilters")} | |||||
| </PrimaryButton> | </PrimaryButton> | ||||
| </Footer> | </Footer> | ||||
| </FilterCardContainer> | </FilterCardContainer> |
| width: 100%; | width: 100%; | ||||
| position: "fixed"; | position: "fixed"; | ||||
| left: 0; | left: 0; | ||||
| display: flex; | |||||
| flex-direction: column; | |||||
| justify-content: space-between; | |||||
| `; | `; | ||||
| export const Title = styled(Typography)` | export const Title = styled(Typography)` | ||||
| font-size: 24px; | font-size: 24px; | ||||
| export const Footer = styled(Box)` | export const Footer = styled(Box)` | ||||
| position: absolute; | |||||
| position: "sticky"; | |||||
| bottom: 0; | bottom: 0; | ||||
| & div button { | |||||
| height: 48px; | |||||
| padding-top: 7px; | |||||
| } | |||||
| & div button:hover { | |||||
| background-color: ${selectedTheme.primaryPurple} !important; | |||||
| color: ${selectedTheme.primaryBackgroundColor} !important; | |||||
| } | |||||
| `; | `; | ||||
| export const ContentContainer = styled(Box)` | |||||
| ` | |||||
| import React, { useEffect, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import DropdownList from "../../../Dropdown/DropdownList/DropdownList"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import IconWithNumber from "../../../Icon/IconWithNumber/IconWithNumber"; | |||||
| import { ReactComponent as DropdownDown } from "../../../../assets/images/svg/dropdownDown.svg"; | |||||
| import { ReactComponent as DropdownUp } from "../../../../assets/images/svg/dropdownUp.svg"; | |||||
| import { ReactComponent as Close } from "../../../../assets/images/svg/closeWhite.svg"; | |||||
| import { ReactComponent as CloseBlack } from "../../../../assets/images/svg/closeBlack.svg"; | |||||
| import { | |||||
| ClearText, | |||||
| SelectedItem, | |||||
| SelectedItemsContainer, | |||||
| } from "./FilterDropdown.styled"; | |||||
| import { TextField } from "../../../TextFields/TextField/TextField"; | |||||
| import DropdownItem from "../../../Dropdown/DropdownItem/DropdownItem"; | |||||
| import { CheckBox } from "../../../CheckBox/CheckBox"; | |||||
| const FilterDropdown = (props) => { | |||||
| const [filtersApplied, setFiltersApplied] = useState([]); | |||||
| const [toSearch, setToSearch] = useState(""); | |||||
| const [dataToShow, setDataToShow] = useState([]); | |||||
| ///IMPLEMENTIRATI PROP FILTERS KOJI MENJA LOKALNO STANJE OVE KOMPONENTE U ZAVISNOSTI OD NJEGOVE PROMENE | |||||
| ///ZA FUNKCIJU PONISTI FILTERE | |||||
| const {data} = props; | |||||
| useEffect(() => { | |||||
| setDataToShow([...data]) | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (toSearch.length > 0) { | |||||
| setDataToShow(data.filter(item => item.string.toLowerCase().includes(toSearch.toLowerCase()))); | |||||
| } else { | |||||
| setDataToShow([...data]); | |||||
| } | |||||
| }, [toSearch]) | |||||
| const handleChange = (item) => { | |||||
| if (filtersApplied.find((p) => p.id === item.id)) { | |||||
| setFiltersApplied([...filtersApplied.filter((p) => p.id !== item.id)]); | |||||
| } else { | |||||
| setFiltersApplied([...filtersApplied, item]); | |||||
| } | |||||
| let indexOfItem = dataToShow.findIndex((p) => p.id === item.id); | |||||
| let items = [...dataToShow]; | |||||
| items[indexOfItem].checked = !item.checked; | |||||
| setDataToShow([...items]); | |||||
| }; | |||||
| const handleDelete = (item) => { | |||||
| setFiltersApplied([...filtersApplied.filter((p) => p.id !== item.id)]); | |||||
| let indexOfItem = dataToShow.findIndex((p) => p.id === item.id); | |||||
| let items = [...dataToShow]; | |||||
| items[indexOfItem].checked = false; | |||||
| setDataToShow([...items]); | |||||
| }; | |||||
| const handleClear = () => { | |||||
| setToSearch(""); | |||||
| }; | |||||
| return ( | |||||
| <DropdownList | |||||
| title={props.title} | |||||
| textcolor={ | |||||
| filtersApplied.length > 0 | |||||
| ? selectedTheme.primaryPurple | |||||
| : selectedTheme.primaryText | |||||
| } | |||||
| dropdownIcon={ | |||||
| <IconWithNumber number={filtersApplied.length}> | |||||
| {props.icon} | |||||
| </IconWithNumber> | |||||
| } | |||||
| toggleIconClosed={<DropdownDown />} | |||||
| toggleIconOpened={<DropdownUp />} | |||||
| fullWidth | |||||
| toggleIconStyles={{ | |||||
| backgroundColor: selectedTheme.primaryIconBackgroundColor, | |||||
| }} | |||||
| headerOptions={ | |||||
| <React.Fragment> | |||||
| <SelectedItemsContainer> | |||||
| {filtersApplied.map((item) => ( | |||||
| <SelectedItem key={item.id} onClick={() => handleDelete(item)}> | |||||
| {item.string}{" "} | |||||
| <Close style={{ position: "relative", top: "3px" }} /> | |||||
| </SelectedItem> | |||||
| ))} | |||||
| </SelectedItemsContainer> | |||||
| <TextField | |||||
| placeholder={"Pretrazite lokacije..."} | |||||
| italicPlaceholder | |||||
| value={toSearch} | |||||
| onChange={(event) => setToSearch(event.target.value)} | |||||
| textsize={"12px"} | |||||
| font={"Open Sans"} | |||||
| fullWidth | |||||
| height={"40px"} | |||||
| containerStyle={{ marginTop: "6px" }} | |||||
| InputProps={{ | |||||
| endAdornment: ( | |||||
| <ClearText onClick={handleClear}> | |||||
| <CloseBlack /> | |||||
| </ClearText> | |||||
| ), | |||||
| }} | |||||
| /> | |||||
| </React.Fragment> | |||||
| } | |||||
| > | |||||
| {dataToShow.map((item) => ( | |||||
| <DropdownItem key={item.id}> | |||||
| <CheckBox | |||||
| leftText={item.string} | |||||
| rightText={item.numberOfProducts} | |||||
| value={item.id} | |||||
| checked={item.checked} | |||||
| onChange={() => handleChange(item)} | |||||
| fullWidth | |||||
| /> | |||||
| </DropdownItem> | |||||
| ))} | |||||
| </DropdownList> | |||||
| ); | |||||
| }; | |||||
| FilterDropdown.propTypes = { | |||||
| children: PropTypes.node, | |||||
| icon: PropTypes.node, | |||||
| data: PropTypes.array, | |||||
| title: PropTypes.string, | |||||
| }; | |||||
| export default FilterDropdown; |
| import React, { useEffect, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import DropdownList from "../../../../Dropdown/DropdownList/DropdownList"; | |||||
| import selectedTheme from "../../../../../themes"; | |||||
| import IconWithNumber from "../../../../Icon/IconWithNumber/IconWithNumber"; | |||||
| import { ReactComponent as DropdownDown } from "../../../../../assets/images/svg/dropdownDown.svg"; | |||||
| import { ReactComponent as DropdownUp } from "../../../../../assets/images/svg/dropdownUp.svg"; | |||||
| import { ReactComponent as Close } from "../../../../../assets/images/svg/closeWhite.svg"; | |||||
| import { ReactComponent as CloseBlack } from "../../../../../assets/images/svg/closeBlack.svg"; | |||||
| import { | |||||
| ClearText, | |||||
| SelectedItem, | |||||
| SelectedItemsContainer, | |||||
| } from "./FilterCheckboxDropdown.styled"; | |||||
| import { TextField } from "../../../../TextFields/TextField/TextField"; | |||||
| import DropdownItem from "../../../../Dropdown/DropdownItem/DropdownItem"; | |||||
| import { CheckBox } from "../../../../CheckBox/CheckBox"; | |||||
| const FilterCheckboxDropdown = (props) => { | |||||
| const [toSearch, setToSearch] = useState(""); | |||||
| const [dataToShow, setDataToShow] = useState([]); | |||||
| const { data } = props; | |||||
| useEffect(() => { | |||||
| setDataToShow([...data]); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (toSearch.length > 0) { | |||||
| setDataToShow( | |||||
| data.filter((item) => | |||||
| item.string.toLowerCase().includes(toSearch.toLowerCase()) | |||||
| ) | |||||
| ); | |||||
| } else { | |||||
| setDataToShow([...data]); | |||||
| } | |||||
| }, [toSearch]); | |||||
| const handleChange = (item) => { | |||||
| if (props.oneValueAllowed) { | |||||
| props.setItemsSelected[item.id]; | |||||
| } else { | |||||
| if (props.filters.find((p) => p.id === item.id)) { | |||||
| props.setItemsSelected((itemsSelected) => [ | |||||
| ...itemsSelected.filter((p) => p !== item.id), | |||||
| ]); | |||||
| } else { | |||||
| props.setItemsSelected((itemsSelected) => [...itemsSelected, item.id]); | |||||
| } | |||||
| } | |||||
| }; | |||||
| const handleDelete = (item) => { | |||||
| props.setItemsSelected([...props.filters.filter((p) => p !== item)]); | |||||
| }; | |||||
| const handleClear = () => { | |||||
| setToSearch(""); | |||||
| }; | |||||
| return ( | |||||
| <DropdownList | |||||
| title={props.title} | |||||
| textcolor={ | |||||
| props.filters.length > 0 | |||||
| ? selectedTheme.primaryPurple | |||||
| : selectedTheme.primaryText | |||||
| } | |||||
| dropdownIcon={ | |||||
| <IconWithNumber number={props.filters.length}> | |||||
| {props.icon} | |||||
| </IconWithNumber> | |||||
| } | |||||
| toggleIconClosed={<DropdownDown />} | |||||
| toggleIconOpened={<DropdownUp />} | |||||
| fullWidth | |||||
| toggleIconStyles={{ | |||||
| backgroundColor: selectedTheme.primaryIconBackgroundColor, | |||||
| }} | |||||
| headerOptions={ | |||||
| <React.Fragment> | |||||
| <SelectedItemsContainer> | |||||
| {props.filters.map((item) => ( | |||||
| <SelectedItem key={item} onClick={() => handleDelete(item)}> | |||||
| {data.find((p) => p.id === item).string} | |||||
| <Close style={{ position: "relative", top: "3px" }} /> | |||||
| </SelectedItem> | |||||
| ))} | |||||
| </SelectedItemsContainer> | |||||
| <TextField | |||||
| placeholder={props.searchPlaceholder} | |||||
| italicPlaceholder | |||||
| value={toSearch} | |||||
| onChange={(event) => setToSearch(event.target.value)} | |||||
| textsize={"12px"} | |||||
| font={"Open Sans"} | |||||
| fullWidth | |||||
| height={"40px"} | |||||
| containerStyle={{ marginTop: "6px" }} | |||||
| InputProps={{ | |||||
| endAdornment: | |||||
| toSearch.length > 0 ? ( | |||||
| <ClearText onClick={handleClear}> | |||||
| <CloseBlack /> | |||||
| </ClearText> | |||||
| ) : ( | |||||
| <React.Fragment /> | |||||
| ), | |||||
| }} | |||||
| /> | |||||
| </React.Fragment> | |||||
| } | |||||
| > | |||||
| {dataToShow.map((item) => ( | |||||
| <DropdownItem key={item.id}> | |||||
| <CheckBox | |||||
| leftText={item.string} | |||||
| rightText={item.numberOfProducts} | |||||
| value={item.id} | |||||
| checked={props.filters.includes(item.id, 0)} | |||||
| onChange={() => handleChange(item)} | |||||
| fullWidth | |||||
| /> | |||||
| </DropdownItem> | |||||
| ))} | |||||
| </DropdownList> | |||||
| ); | |||||
| }; | |||||
| FilterCheckboxDropdown.propTypes = { | |||||
| children: PropTypes.node, | |||||
| icon: PropTypes.node, | |||||
| data: PropTypes.array, | |||||
| title: PropTypes.string, | |||||
| oneValueAllowed: PropTypes.bool, | |||||
| searchPlaceholder: PropTypes.string, | |||||
| setItemsSelected: PropTypes.func, | |||||
| filters: PropTypes.array, | |||||
| }; | |||||
| FilterCheckboxDropdown.defaultProps = { | |||||
| oneValueAllowed: false, | |||||
| }; | |||||
| export default FilterCheckboxDropdown; |
| import { Box } from "@mui/material"; | import { Box } from "@mui/material"; | ||||
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import selectedTheme from "../../../../themes"; | |||||
| import selectedTheme from "../../../../../themes"; | |||||
| export const SelectedItemsContainer = styled(Box)` | export const SelectedItemsContainer = styled(Box)` | ||||
| display: flex; | display: flex; | ||||
| height: 22px; | height: 22px; | ||||
| `; | `; | ||||
| export const ClearText = styled(Box)` | export const ClearText = styled(Box)` | ||||
| padding-top: 1px; | |||||
| border-radius: 100%; | |||||
| cursor: pointer; | |||||
| padding-right: 2px; | |||||
| position: relative; | |||||
| left: 6px; | |||||
| width: 21px; | |||||
| height: 21px; | |||||
| &:hover { | |||||
| background-color: ${selectedTheme.primaryIconBackgroundColor}; | |||||
| } | |||||
| ` | |||||
| padding-top: 1px; | |||||
| border-radius: 100%; | |||||
| cursor: pointer; | |||||
| padding-right: 2px; | |||||
| position: relative; | |||||
| left: 6px; | |||||
| width: 21px; | |||||
| height: 21px; | |||||
| &:hover { | |||||
| background-color: ${selectedTheme.primaryIconBackgroundColor}; | |||||
| } | |||||
| `; |
| import React, { useEffect, useState } from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import DropdownList from "../../../../Dropdown/DropdownList/DropdownList"; | |||||
| import selectedTheme from "../../../../../themes"; | |||||
| import { ReactComponent as DropdownDown } from "../../../../../assets/images/svg/dropdownDown.svg"; | |||||
| import { ReactComponent as DropdownUp } from "../../../../../assets/images/svg/dropdownUp.svg"; | |||||
| import { ReactComponent as CloseBlack } from "../../../../../assets/images/svg/closeBlack.svg"; | |||||
| import { ClearText } from "./FilterRadioDropdown.styled"; | |||||
| import { TextField } from "../../../../TextFields/TextField/TextField"; | |||||
| import DropdownItem from "../../../../Dropdown/DropdownItem/DropdownItem"; | |||||
| import RadioButton from "../../../../Radio/Button/RadioButton"; | |||||
| import RadioGroup from "../../../../Radio/Group/RadioGroup"; | |||||
| const FilterRadioDropdown = (props) => { | |||||
| const [toSearch, setToSearch] = useState(""); | |||||
| const [dataToShow, setDataToShow] = useState([]); | |||||
| const { data } = props; | |||||
| useEffect(() => { | |||||
| setDataToShow([...data]); | |||||
| }, []); | |||||
| useEffect(() => { | |||||
| if (toSearch.length > 0) { | |||||
| setDataToShow( | |||||
| data.filter((item) => | |||||
| item.string.toLowerCase().includes(toSearch.toLowerCase()) | |||||
| ) | |||||
| ); | |||||
| } else { | |||||
| setDataToShow([...data]); | |||||
| } | |||||
| }, [toSearch]); | |||||
| const handleClear = () => { | |||||
| setToSearch(""); | |||||
| }; | |||||
| const handleChange = (value) => { | |||||
| props.setSelected(value); | |||||
| }; | |||||
| return ( | |||||
| <DropdownList | |||||
| title={props.title} | |||||
| textcolor={ | |||||
| props.selected !== 0 | |||||
| ? selectedTheme.primaryPurple | |||||
| : selectedTheme.primaryText | |||||
| } | |||||
| dropdownIcon={props.icon} | |||||
| toggleIconClosed={<DropdownDown />} | |||||
| toggleIconOpened={<DropdownUp />} | |||||
| fullWidth | |||||
| toggleIconStyles={{ | |||||
| backgroundColor: selectedTheme.primaryIconBackgroundColor, | |||||
| }} | |||||
| headerOptions={ | |||||
| <React.Fragment> | |||||
| <TextField | |||||
| placeholder={props.searchPlaceholder} | |||||
| italicPlaceholder | |||||
| value={toSearch} | |||||
| onChange={(event) => setToSearch(event.target.value)} | |||||
| textsize={"12px"} | |||||
| font={"Open Sans"} | |||||
| fullWidth | |||||
| height={"40px"} | |||||
| containerStyle={{ marginTop: "6px" }} | |||||
| InputProps={{ | |||||
| endAdornment: | |||||
| toSearch.length > 0 ? ( | |||||
| <ClearText onClick={handleClear}> | |||||
| <CloseBlack /> | |||||
| </ClearText> | |||||
| ) : ( | |||||
| <React.Fragment /> | |||||
| ), | |||||
| }} | |||||
| /> | |||||
| </React.Fragment> | |||||
| } | |||||
| > | |||||
| <RadioGroup onChange={(event) => handleChange(event.target.value)}> | |||||
| {dataToShow.map((item) => ( | |||||
| <DropdownItem key={item.id}> | |||||
| <RadioButton | |||||
| value={item.id} | |||||
| label={item.string} | |||||
| number={item.numberOfProducts} | |||||
| fullWidth | |||||
| checked={props.selected.toString() === item.id.toString()} | |||||
| onChange={handleChange} | |||||
| /> | |||||
| </DropdownItem> | |||||
| ))} | |||||
| </RadioGroup> | |||||
| </DropdownList> | |||||
| ); | |||||
| }; | |||||
| FilterRadioDropdown.propTypes = { | |||||
| children: PropTypes.node, | |||||
| icon: PropTypes.node, | |||||
| data: PropTypes.array, | |||||
| title: PropTypes.string, | |||||
| oneValueAllowed: PropTypes.bool, | |||||
| fullWidth: PropTypes.bool, | |||||
| searchPlaceholder: PropTypes.string, | |||||
| setSelected: PropTypes.func, | |||||
| selected: PropTypes.number, | |||||
| }; | |||||
| FilterRadioDropdown.defaultProps = { | |||||
| oneValueAllowed: false, | |||||
| fullWidth: false, | |||||
| }; | |||||
| export default FilterRadioDropdown; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../../themes"; | |||||
| export const SelectedItemsContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| flex-wrap: wrap; | |||||
| margin-top: 5px; | |||||
| `; | |||||
| export const ClearText = styled(Box)` | |||||
| padding-top: 1px; | |||||
| border-radius: 100%; | |||||
| cursor: pointer; | |||||
| padding-right: 2px; | |||||
| position: relative; | |||||
| left: 6px; | |||||
| width: 21px; | |||||
| height: 21px; | |||||
| &:hover { | |||||
| background-color: ${selectedTheme.primaryIconBackgroundColor}; | |||||
| } | |||||
| ` |
| export default [{ | |||||
| export default [[{ | |||||
| string: "Beograd", | string: "Beograd", | ||||
| numberOfProducts: 17, | numberOfProducts: 17, | ||||
| id: 0, | id: 0, | ||||
| numberOfProducts: 23, | numberOfProducts: 23, | ||||
| id: 5, | id: 5, | ||||
| checked: false | checked: false | ||||
| }]; | |||||
| }], | |||||
| [ | |||||
| { | |||||
| string: "SVE KATEGORIJE", | |||||
| numberOfProducts: 259, | |||||
| id: 0, | |||||
| }, | |||||
| { | |||||
| string: "Kategorija 1", | |||||
| numberOfProducts: 46, | |||||
| id: 1, | |||||
| }, | |||||
| { | |||||
| string: "Kategorija 2", | |||||
| numberOfProducts: 26, | |||||
| id: 2, | |||||
| }, | |||||
| { | |||||
| string: "Kategorija 3", | |||||
| numberOfProducts: 91, | |||||
| id: 3, | |||||
| }, | |||||
| { | |||||
| string: "Kategorija 4", | |||||
| numberOfProducts: 23, | |||||
| id: 4, | |||||
| }, | |||||
| { | |||||
| string: "Kategorija 5", | |||||
| numberOfProducts: 20, | |||||
| id: 5, | |||||
| }, | |||||
| ]]; |
| color: PropTypes.string, | color: PropTypes.string, | ||||
| name: PropTypes.string, | name: PropTypes.string, | ||||
| leftText: PropTypes.string, | leftText: PropTypes.string, | ||||
| rightText: PropTypes.string, | |||||
| rightText: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), | |||||
| maxWidth: PropTypes.string, | maxWidth: PropTypes.string, | ||||
| checked: PropTypes.bool, | checked: PropTypes.bool, | ||||
| value: PropTypes.number, | value: PropTypes.number, |
| padding: 6px; | padding: 6px; | ||||
| `; | `; | ||||
| export const FormControlLabelStyled = styled(FormControlLabel)` | export const FormControlLabelStyled = styled(FormControlLabel)` | ||||
| font-family: "Open Sans"; | |||||
| font-size: 12px; | |||||
| ${(props) => | ${(props) => | ||||
| props.fullWidth && | props.fullWidth && | ||||
| ` | ` | ||||
| flex: 1; | flex: 1; | ||||
| `} | `} | ||||
| margin-right: 0; | margin-right: 0; | ||||
| & label { | |||||
| font-family: "Open Sans"; | |||||
| font-size: 12px; | |||||
| } | |||||
| & span:nth-child(1) svg { | |||||
| width: 18px; | |||||
| height: 18px; | |||||
| } | |||||
| & span:nth-child(2) { | & span:nth-child(2) { | ||||
| flex: 1; | flex: 1; | ||||
| } | } |
| Label.propTypes = { | Label.propTypes = { | ||||
| onClick: PropTypes.func, | onClick: PropTypes.func, | ||||
| leftText: PropTypes.string, | leftText: PropTypes.string, | ||||
| rightText: PropTypes.string, | |||||
| rightText: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), | |||||
| maxWidth: PropTypes.string, | maxWidth: PropTypes.string, | ||||
| }; | }; |
| ` | ` | ||||
| export const LeftLabel = styled(FormLabel)` | export const LeftLabel = styled(FormLabel)` | ||||
| font-family: "Open Sans"; | |||||
| overflow: hidden; | overflow: hidden; | ||||
| text-overflow: ellipsis; | text-overflow: ellipsis; | ||||
| white-space: nowrap; | white-space: nowrap; | ||||
| max-width: 100px; | max-width: 100px; | ||||
| cursor: pointer; | cursor: pointer; | ||||
| color: ${selectedTheme.primaryText}; | color: ${selectedTheme.primaryText}; | ||||
| font-family: "Open Sans"; | |||||
| ` | ` |
| <DropdownListContainer fullWidth={props.fullWidth}> | <DropdownListContainer fullWidth={props.fullWidth}> | ||||
| <DropdownHeader> | <DropdownHeader> | ||||
| {props.dropdownIcon && ( | {props.dropdownIcon && ( | ||||
| <DropdownIcon>{props.dropdownIcon}</DropdownIcon> | |||||
| <DropdownIcon onClick={() => setListShown((prevState) => !prevState)}> | |||||
| {props.dropdownIcon} | |||||
| </DropdownIcon> | |||||
| )} | )} | ||||
| <DropdownTitle onClick={() => setListShown((prevState) => !prevState)} textcolor={props.textcolor}> | |||||
| <DropdownTitle | |||||
| onClick={() => setListShown((prevState) => !prevState)} | |||||
| textcolor={props.textcolor} | |||||
| > | |||||
| {props.title} | {props.title} | ||||
| </DropdownTitle> | </DropdownTitle> | ||||
| {listShown ? ( | {listShown ? ( |
| export const DropdownListContainer = styled(Box)` | export const DropdownListContainer = styled(Box)` | ||||
| width: ${(props) => | width: ${(props) => | ||||
| props.fullWidth ? "100%" : props.width ? props.width : "250px"}; | props.fullWidth ? "100%" : props.width ? props.width : "250px"}; | ||||
| padding: 8px; | |||||
| padding: 8px 0; | |||||
| `; | `; | ||||
| export const DropdownTitle = styled(Typography)` | export const DropdownTitle = styled(Typography)` | ||||
| export const ListContainer = styled(Box)` | export const ListContainer = styled(Box)` | ||||
| padding-left: 15px; | padding-left: 15px; | ||||
| margin-left: 15px; | |||||
| `; | `; | ||||
| export const DropdownHeader = styled(Box)` | export const DropdownHeader = styled(Box)` | ||||
| flex-direction: row; | flex-direction: row; | ||||
| `; | `; | ||||
| export const DropdownOptions = styled(Box)` | export const DropdownOptions = styled(Box)` | ||||
| padding-left: 7px; | |||||
| `; | `; | ||||
| export const ToggleContainer = styled(Box)` | export const ToggleContainer = styled(Box)` | ||||
| display: ${(props) => (props.shouldShow ? "block" : "none")}; | display: ${(props) => (props.shouldShow ? "block" : "none")}; |
| return ( | return ( | ||||
| <MainLayoutContainer maxWidth={true}> | <MainLayoutContainer maxWidth={true}> | ||||
| {props.children} | {props.children} | ||||
| <Grid container xs={12} maxHeight="lg"> | |||||
| <LeftCard item xs={3}> | |||||
| <Grid container lg={12} maxHeight="lg"> | |||||
| <LeftCard item xs={2} lg={3} xl={2.4} md={4}> | |||||
| {props.leftCard} | {props.leftCard} | ||||
| </LeftCard> | </LeftCard> | ||||
| <Content item xs={8}> | |||||
| <Content item xs={10} lg={9} xl={9.6} md={8}> | |||||
| {props.content} | {props.content} | ||||
| </Content> | </Content> | ||||
| </Grid> | </Grid> |
| const Link = (props) => { | const Link = (props) => { | ||||
| return ( | return ( | ||||
| <LinkStyled {...props} href={props.href}> | |||||
| <LinkStyled {...props} href={props.href} onClick={props.onClick}> | |||||
| {props.children} | {props.children} | ||||
| </LinkStyled> | </LinkStyled> | ||||
| ); | ); | ||||
| align: PropTypes.oneOf(["left", "right", "center"]), | align: PropTypes.oneOf(["left", "right", "center"]), | ||||
| textsize: PropTypes.string, | textsize: PropTypes.string, | ||||
| lineheight: PropTypes.string, | lineheight: PropTypes.string, | ||||
| onClick: PropTypes.func, | |||||
| }; | }; | ||||
| Link.defaultProps = { | Link.defaultProps = { | ||||
| font: "Poppins", | font: "Poppins", |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| FormControlLabelStyled, | |||||
| RadioButtonContainer, | |||||
| RadioButtonStyled, | |||||
| } from "./RadioButton.styled"; | |||||
| import { ReactComponent as RadioChecked } from "../../../assets/images/svg/radio-checked.svg"; | |||||
| import { ReactComponent as RadioUnchecked } from "../../../assets/images/svg/radio-unchecked.svg"; | |||||
| import { Label } from "../../CheckBox/Label"; | |||||
| const RadioButton = (props) => { | |||||
| return ( | |||||
| <RadioButtonContainer fullWidth={props.fullWidth}> | |||||
| <FormControlLabelStyled | |||||
| value={props.value} | |||||
| fullWidth={props.fullWidth} | |||||
| control={ | |||||
| <RadioButtonStyled | |||||
| icon={<RadioUnchecked />} | |||||
| onChange={() => props.onChange(props.value)} | |||||
| checkedIcon={<RadioChecked />} | |||||
| checked={props.checked} | |||||
| /> | |||||
| } | |||||
| label={ | |||||
| <Label | |||||
| leftText={props.label} | |||||
| rightText={props.number} | |||||
| onClick={() => props.onChange(props.value)} | |||||
| /> | |||||
| } | |||||
| /> | |||||
| </RadioButtonContainer> | |||||
| ); | |||||
| }; | |||||
| RadioButton.propTypes = { | |||||
| children: PropTypes.node, | |||||
| value: PropTypes.number, | |||||
| label: PropTypes.string, | |||||
| number: PropTypes.number, | |||||
| fullWidth: PropTypes.bool, | |||||
| checked: PropTypes.bool, | |||||
| onChange: PropTypes.func, | |||||
| }; | |||||
| RadioButton.defaultProps = { | |||||
| fullWidth: false, | |||||
| }; | |||||
| export default RadioButton; |
| import { Box, FormControlLabel, Radio } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const RadioButtonContainer = styled(Box)` | |||||
| ${(props) => | |||||
| props.fullWidth && | |||||
| ` | |||||
| width: 100%; | |||||
| display: flex; | |||||
| flex: 1; | |||||
| `} | |||||
| `; | |||||
| export const RadioButtonStyled = styled(Radio)` | |||||
| margin-top: 5px; | |||||
| margin-bottom: 5px; | |||||
| margin-right: 9px; | |||||
| width: 14px; | |||||
| height: 14px; | |||||
| `; | |||||
| export const FormControlLabelStyled = styled(FormControlLabel)` | |||||
| ${(props) => | |||||
| props.fullWidth && | |||||
| ` | |||||
| width: 100%; | |||||
| display: flex; | |||||
| flex: 1; | |||||
| `} | |||||
| margin-right: 0; | |||||
| & label { | |||||
| font-family: "Open Sans"; | |||||
| font-size: 12px; | |||||
| } | |||||
| & span:nth-child(1) svg { | |||||
| width: 16px; | |||||
| height: 16px; | |||||
| } | |||||
| & span:nth-child(2) { | |||||
| flex: 1; | |||||
| } | |||||
| `; |
| import React from 'react' | |||||
| import PropTypes from 'prop-types' | |||||
| import { RadioGroupContainer } from './RadioGroup.styled' | |||||
| const RadioGroup = (props) => { | |||||
| return ( | |||||
| <RadioGroupContainer onChange={props.onChange} value={props.value}> | |||||
| {props.children} | |||||
| </RadioGroupContainer> | |||||
| ) | |||||
| } | |||||
| RadioGroup.propTypes = { | |||||
| children: PropTypes.node, | |||||
| onChange: PropTypes.func, | |||||
| value: PropTypes.any, | |||||
| defaultValue: PropTypes.any, | |||||
| } | |||||
| export default RadioGroup |
| import { RadioGroup } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| export const RadioGroupContainer = styled(RadioGroup)` | |||||
| padding-left: 5px; | |||||
| width: 100%; | |||||
| ` |
| label: 'Obnovite lozinku', | label: 'Obnovite lozinku', | ||||
| }, | }, | ||||
| }, | }, | ||||
| filters: { | |||||
| title: "Filteri", | |||||
| cancel: "Poništi filtere", | |||||
| usefilters: 'Primeni filtere', | |||||
| categories: { | |||||
| title: "Kategorija", | |||||
| placeholder: 'Pretraži kategorije...' | |||||
| }, | |||||
| subcategories: { | |||||
| title: "Podkategorija", | |||||
| placeholder: "Pretraži podkategorije..." | |||||
| }, | |||||
| location: { | |||||
| title: "Lokacija", | |||||
| placeholder: "Pretraži gradove..." | |||||
| } | |||||
| } | |||||
| } | } |
| return ( | return ( | ||||
| <HomePageContainer maxWidth={true}> | <HomePageContainer maxWidth={true}> | ||||
| <Navbar /> | <Navbar /> | ||||
| <MainLayout leftCard={<FilterCard />} /> | |||||
| <MainLayout leftCard={<FilterCard />} content={<div></div>}/> | |||||
| {/* <Box sx={{ mt: 4, mx: 4 }}> | {/* <Box sx={{ mt: 4, mx: 4 }}> | ||||
| <GridStyled container justifyContent="space-between"> | <GridStyled container justifyContent="space-between"> | ||||
| <GridStyled item xs={12} md={3}> | <GridStyled item xs={12} md={3}> |