complete frontend restyling
This commit is contained in:
10
frontend-react/src/assets/checkboxAndRadioStyle.css
Normal file
10
frontend-react/src/assets/checkboxAndRadioStyle.css
Normal file
@@ -0,0 +1,10 @@
|
||||
.radio-style {
|
||||
color: #e91e63 !important;
|
||||
}
|
||||
|
||||
.checkbox-style {
|
||||
color: #e91e63 !important;
|
||||
}
|
||||
.label-style {
|
||||
color: white;
|
||||
}
|
||||
26
frontend-react/src/assets/dashboardStyle.js
Normal file
26
frontend-react/src/assets/dashboardStyle.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import { drawerWidth, transition } from "./globalStyle";
|
||||
|
||||
const appStyle = theme => ({
|
||||
wrapper: {
|
||||
top: "0",
|
||||
display: "grid",
|
||||
minHeight: "750px",
|
||||
"grid-template-columns": `${drawerWidth}px 1fr`,
|
||||
"grid-template-areas": `"sidebar content"`,
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
"grid-template-areas": `"sidebar" "content"`,
|
||||
"grid-template-columns": "1fr",
|
||||
"grid-template-rows": "auto 1fr"
|
||||
}
|
||||
},
|
||||
mainPanel: {
|
||||
...transition,
|
||||
overflowScrolling: "touch",
|
||||
"grid-area": "content",
|
||||
zIndex: "1",
|
||||
backgroundColor: "#272727",
|
||||
backgroundImage: "linear-gradient(180deg,#272727, #21525f)"
|
||||
}
|
||||
});
|
||||
|
||||
export default appStyle;
|
||||
42
frontend-react/src/assets/globalStyle.js
Normal file
42
frontend-react/src/assets/globalStyle.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const drawerWidth = 360;
|
||||
|
||||
const transition = {
|
||||
transition: "all 0.33s cubic-bezier(0.685, 0.0473, 0.346, 1)"
|
||||
};
|
||||
|
||||
const boxShadow = {
|
||||
boxShadow:
|
||||
"0 10px 30px -12px rgba(0, 0, 0, 0.42), 0 4px 25px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2)"
|
||||
};
|
||||
|
||||
const defaultFont = {
|
||||
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
|
||||
fontWeight: "300",
|
||||
lineHeight: "1.5em"
|
||||
};
|
||||
|
||||
const primaryColor = "#e91e63";
|
||||
|
||||
const primaryBoxShadow = {
|
||||
boxShadow:
|
||||
"0 4px 20px 0px rgba(0, 0, 0, 0.14), 0 7px 10px -5px rgba(233, 30, 99, 0.4)"
|
||||
};
|
||||
|
||||
const defaultBoxShadow = {
|
||||
border: "0",
|
||||
borderRadius: "3px",
|
||||
boxShadow:
|
||||
"0 10px 20px -12px rgba(0, 0, 0, 0.42), 0 3px 20px 0px rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(0, 0, 0, 0.2)",
|
||||
padding: "10px 0",
|
||||
transition: "all 150ms ease 0s"
|
||||
};
|
||||
|
||||
export {
|
||||
drawerWidth,
|
||||
transition,
|
||||
boxShadow,
|
||||
defaultFont,
|
||||
primaryColor,
|
||||
primaryBoxShadow,
|
||||
defaultBoxShadow
|
||||
};
|
||||
BIN
frontend-react/src/assets/img/reactlogo.png
Normal file
BIN
frontend-react/src/assets/img/reactlogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.6 KiB |
BIN
frontend-react/src/assets/img/sidebar-1.jpg
Normal file
BIN
frontend-react/src/assets/img/sidebar-1.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 272 KiB |
28
frontend-react/src/assets/rangeStyle.css
Normal file
28
frontend-react/src/assets/rangeStyle.css
Normal file
@@ -0,0 +1,28 @@
|
||||
.rc-slider-handle {
|
||||
border: solid 2px #e91e63 !important;
|
||||
}
|
||||
.rc-slider-handle:hover {
|
||||
border: solid 2px #e91e63 !important;
|
||||
}
|
||||
.rc-slider-rail {
|
||||
background-color: #e91e63 !important;
|
||||
width: 20px;
|
||||
}
|
||||
.rc-slider-track {
|
||||
background-color: grey !important;
|
||||
}
|
||||
.input-style:after {
|
||||
border-bottom: 1px solid #e91e63 !important;
|
||||
}
|
||||
.input-style {
|
||||
color: white !important;
|
||||
width: 80% !important;
|
||||
margin: 0 auto !important;
|
||||
position: relative !important;
|
||||
display: block !important;
|
||||
margin: 10px auto !important;
|
||||
}
|
||||
.rc-slider {
|
||||
width: 80% !important;
|
||||
margin: 0 auto !important;
|
||||
}
|
||||
171
frontend-react/src/assets/sidebarStyle.js
Normal file
171
frontend-react/src/assets/sidebarStyle.js
Normal file
@@ -0,0 +1,171 @@
|
||||
import {
|
||||
boxShadow,
|
||||
defaultFont,
|
||||
primaryColor,
|
||||
primaryBoxShadow
|
||||
} from "./globalStyle";
|
||||
|
||||
const sidebarStyle = theme => ({
|
||||
drawerPaper: {
|
||||
border: "none",
|
||||
position: "relative",
|
||||
"overflow-y": "auto",
|
||||
"overflow-x": "none",
|
||||
zIndex: "1",
|
||||
...boxShadow,
|
||||
"grid-area": "sidebar",
|
||||
[theme.breakpoints.down("sm")]: {
|
||||
position: "relative"
|
||||
}
|
||||
},
|
||||
logo: {
|
||||
position: "relative",
|
||||
padding: "15px 15px",
|
||||
zIndex: "4",
|
||||
"&:after": {
|
||||
content: '""',
|
||||
position: "absolute",
|
||||
bottom: "0",
|
||||
|
||||
height: "1px",
|
||||
right: "15px",
|
||||
width: "calc(100% - 30px)",
|
||||
backgroundColor: "rgba(180, 180, 180, 0.3)"
|
||||
}
|
||||
},
|
||||
logoLink: {
|
||||
...defaultFont,
|
||||
textTransform: "uppercase",
|
||||
padding: "5px 0",
|
||||
display: "block",
|
||||
fontSize: "18px",
|
||||
textAlign: "left",
|
||||
fontWeight: "400",
|
||||
lineHeight: "30px",
|
||||
textDecoration: "none",
|
||||
backgroundColor: "transparent",
|
||||
"&,&:hover": {
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
},
|
||||
logoImage: {
|
||||
width: "30px",
|
||||
display: "inline-block",
|
||||
maxHeight: "30px",
|
||||
marginLeft: "10px",
|
||||
marginRight: "15px"
|
||||
},
|
||||
img: {
|
||||
width: "35px",
|
||||
top: "22px",
|
||||
position: "absolute",
|
||||
verticalAlign: "middle",
|
||||
border: "0"
|
||||
},
|
||||
background: {
|
||||
position: "absolute",
|
||||
zIndex: "1",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "block",
|
||||
top: "0",
|
||||
left: "0",
|
||||
backgroundSize: "cover",
|
||||
backgroundPosition: "center center",
|
||||
"&:after": {
|
||||
position: "absolute",
|
||||
zIndex: "3",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
content: '""',
|
||||
display: "block",
|
||||
background: "#000",
|
||||
opacity: ".8"
|
||||
}
|
||||
},
|
||||
list: {
|
||||
marginTop: "20px",
|
||||
paddingLeft: "0",
|
||||
paddingTop: "0",
|
||||
paddingBottom: "0",
|
||||
marginBottom: "0",
|
||||
listStyle: "none",
|
||||
position: "unset"
|
||||
},
|
||||
item: {
|
||||
position: "relative",
|
||||
display: "block",
|
||||
textDecoration: "none",
|
||||
"&:hover,&:focus,&:visited,&": {
|
||||
color: "#FFFFFF"
|
||||
}
|
||||
},
|
||||
itemLink: {
|
||||
width: "auto",
|
||||
transition: "all 300ms linear",
|
||||
margin: "10px 15px 0",
|
||||
borderRadius: "3px",
|
||||
position: "relative",
|
||||
display: "block",
|
||||
padding: "10px 15px",
|
||||
backgroundColor: "transparent",
|
||||
...defaultFont
|
||||
},
|
||||
itemIcon: {
|
||||
width: "24px",
|
||||
height: "30px",
|
||||
fontSize: "24px",
|
||||
lineHeight: "30px",
|
||||
float: "left",
|
||||
marginRight: "15px",
|
||||
textAlign: "center",
|
||||
verticalAlign: "middle",
|
||||
color: "rgba(255, 255, 255, 0.8)"
|
||||
},
|
||||
itemText: {
|
||||
...defaultFont,
|
||||
margin: "0",
|
||||
lineHeight: "30px",
|
||||
fontSize: "14px",
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
whiteFont: {
|
||||
color: "#FFFFFF"
|
||||
},
|
||||
|
||||
sidebarWrapper: {
|
||||
width: "360px",
|
||||
position: "relative",
|
||||
overflow: "auto",
|
||||
zIndex: "4",
|
||||
overflowScrolling: "touch"
|
||||
},
|
||||
whiteText: {
|
||||
zIndex: "5000",
|
||||
color: "white"
|
||||
},
|
||||
collapsedItemStyle: {
|
||||
zIndex: "5000",
|
||||
color: "white",
|
||||
"&:hover": {
|
||||
backgroundColor: primaryColor,
|
||||
color: "#FFFFFF",
|
||||
...primaryBoxShadow
|
||||
},
|
||||
cursor: "pointer"
|
||||
},
|
||||
collapse: {
|
||||
width: "80%",
|
||||
margin: "0 auto"
|
||||
},
|
||||
checkedItem: {
|
||||
backgroundColor: primaryColor,
|
||||
color: "#FFFFFF",
|
||||
...primaryBoxShadow
|
||||
},
|
||||
subOptionIndent: {
|
||||
paddingLeft: "20px"
|
||||
}
|
||||
});
|
||||
|
||||
export default sidebarStyle;
|
||||
@@ -1,26 +1,20 @@
|
||||
import React from "react";
|
||||
import Select from "react-select";
|
||||
import PropTypes from "prop-types";
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
CATEGORY_SELECT,
|
||||
ITEMS_CHANGED,
|
||||
USER_DATA_CHANGED
|
||||
} from "constants/actionTypes";
|
||||
import { hoc, areObjectEqual } from "utils/helpers";
|
||||
import { ITEMS_CHANGED, USER_DATA_CHANGED } from "constants/actionTypes";
|
||||
import { areObjectEqual } from "utils/helpers";
|
||||
import { createOlxLink } from "utils/createOlxLink";
|
||||
import axios from "axios";
|
||||
|
||||
import * as Vozila from "./categories/Vozila";
|
||||
import * as Nekretnine from "./categories/Nekretnine";
|
||||
import image from "assets/img/sidebar-1.jpg";
|
||||
import logo from "assets/img/reactlogo.png";
|
||||
|
||||
import DeepCategoryWrapper from "components/widgets/DeepCategoryWrapper";
|
||||
import Sidebar from "components/Sidebar.js";
|
||||
import ItemsContainer from "./items/itemscontainer/ItemsContainer";
|
||||
import NotificationModal from "./NotificationModal";
|
||||
|
||||
const options = [
|
||||
{ value: "Vozila", label: "Vozila" },
|
||||
{ value: "Nekretnine", label: "Nekretnine" }
|
||||
];
|
||||
import dashboardStyle from "assets/dashboardStyle.js";
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
@@ -33,7 +27,6 @@ const mapStateToProps = state => {
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onCategoryChanged: option => dispatch({ type: CATEGORY_SELECT, option }),
|
||||
onItemsChanged: items => dispatch({ type: ITEMS_CHANGED, items }),
|
||||
onUserDataChange: change => dispatch({ type: USER_DATA_CHANGED, ...change })
|
||||
});
|
||||
@@ -84,32 +77,29 @@ class App extends React.Component {
|
||||
lastUpdateTime = Date.now();
|
||||
}
|
||||
}
|
||||
handleChange = selectedOption => {
|
||||
this.props.onCategoryChanged(selectedOption);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { category, items } = this.props;
|
||||
const { items, classes } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
value={category}
|
||||
onChange={this.handleChange}
|
||||
options={options}
|
||||
/>
|
||||
{hoc(category && category.value, {
|
||||
Vozila: <DeepCategoryWrapper {...Vozila.properties} />,
|
||||
Nekretnine: <DeepCategoryWrapper {...Nekretnine.properties} />
|
||||
})}
|
||||
<ItemsContainer />
|
||||
{items.length ? <NotificationModal /> : null}
|
||||
<div className={classes.wrapper}>
|
||||
<Sidebar logoText={"Market Alarm"} logo={logo} image={image} />
|
||||
|
||||
<div className={classes.mainPanel}>
|
||||
<ItemsContainer />
|
||||
{items.length ? <NotificationModal /> : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
App.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(App);
|
||||
export default withStyles(dashboardStyle)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(App)
|
||||
);
|
||||
|
||||
@@ -19,6 +19,22 @@ const modalStyle = function() {
|
||||
};
|
||||
};
|
||||
|
||||
const buttonStyle = function() {
|
||||
return {
|
||||
width: "100px",
|
||||
margin: "0 auto",
|
||||
position: "relative",
|
||||
borderRadius: "8px",
|
||||
display: "block",
|
||||
padding: "10px 10px",
|
||||
textAlign: "center",
|
||||
marginBottom: "20px",
|
||||
color: "white",
|
||||
backgroundColor: "#e91e63",
|
||||
border: "1px solid #e91e63"
|
||||
};
|
||||
};
|
||||
|
||||
class NotificationModal extends React.Component {
|
||||
handleOpen = () => {
|
||||
this.props.onModalOpen();
|
||||
@@ -50,7 +66,9 @@ class NotificationModal extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button onClick={this.handleOpen}>Open Modal</button>
|
||||
<button style={buttonStyle()} onClick={this.handleOpen}>
|
||||
Open Modal
|
||||
</button>
|
||||
|
||||
<div style={modalStyle()} aria-labelledby="modal-label" hidden={!modal}>
|
||||
<div>
|
||||
|
||||
135
frontend-react/src/components/Sidebar.js
Normal file
135
frontend-react/src/components/Sidebar.js
Normal file
@@ -0,0 +1,135 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import Dashboard from "@material-ui/icons/Dashboard";
|
||||
import ExpandLess from "@material-ui/icons/ExpandLess";
|
||||
import ExpandMore from "@material-ui/icons/ExpandMore";
|
||||
import Collapse from "@material-ui/core/Collapse";
|
||||
import StarBorder from "@material-ui/icons/StarBorder";
|
||||
|
||||
import sidebarStyle from "assets/sidebarStyle.js";
|
||||
import CollapseWrapperStyled from "components/widgets/CollapseWrapperStyled";
|
||||
import DeepCategoryWrapper from "./widgets/DeepCategoryWrapper";
|
||||
import { hoc } from "utils/helpers";
|
||||
|
||||
import * as Vozila from "./categories/Vozila";
|
||||
import * as Nekretnine from "./categories/Nekretnine";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { CATEGORY_SELECT } from "constants/actionTypes";
|
||||
|
||||
const options = [
|
||||
{ value: "Vozila", label: "Vozila" },
|
||||
{ value: "Nekretnine", label: "Nekretnine" }
|
||||
];
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
category: state.category
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onCategoryChanged: option => dispatch({ type: CATEGORY_SELECT, option })
|
||||
});
|
||||
|
||||
class Sidebar extends React.Component {
|
||||
handleCategoryChange = selectedOption => {
|
||||
this.props.onCategoryChanged(selectedOption);
|
||||
};
|
||||
render() {
|
||||
const { classes, logo, image, logoText, category } = this.props;
|
||||
|
||||
return (
|
||||
<div className={classes.drawerPaper}>
|
||||
<div className={classes.logo}>
|
||||
<a href="https://www.creative-tim.com" className={classes.logoLink}>
|
||||
<div className={classes.logoImage}>
|
||||
<img src={logo} alt="logo" className={classes.img} />
|
||||
</div>
|
||||
{logoText}
|
||||
</a>
|
||||
</div>
|
||||
<div className={classes.sidebarWrapper}>
|
||||
<List role="menu">
|
||||
<ListItem className={classes.whiteText} onClick={this.handleClick}>
|
||||
<ListItemIcon className={classes.whiteText}>
|
||||
<Dashboard />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.whiteText}
|
||||
inset
|
||||
primary="Kategorija"
|
||||
disableTypography={true}
|
||||
/>
|
||||
{true ? <ExpandLess /> : <ExpandMore />}
|
||||
</ListItem>
|
||||
<Collapse in={true} timeout="auto" unmountOnExit>
|
||||
<List disablePadding>
|
||||
{options.map(({ label, value }, index) => (
|
||||
<ListItem
|
||||
onClick={() => this.handleCategoryChange({ label, value })}
|
||||
className={
|
||||
classes.nested +
|
||||
" " +
|
||||
classes.collapsedItemStyle +
|
||||
" " +
|
||||
(category && category.value === value
|
||||
? classes.checkedItem
|
||||
: "")
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
<ListItemIcon className={classes.whiteText}>
|
||||
<StarBorder />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.whiteText}
|
||||
primary={label}
|
||||
disableTypography={true}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Collapse>
|
||||
|
||||
{hoc(category && category.value, {
|
||||
Vozila: (
|
||||
<CollapseWrapperStyled componentName="Podkategorija">
|
||||
<DeepCategoryWrapper {...Vozila.properties} />
|
||||
</CollapseWrapperStyled>
|
||||
),
|
||||
Nekretnine: (
|
||||
<CollapseWrapperStyled componentName="Podkategorija">
|
||||
<DeepCategoryWrapper {...Nekretnine.properties} />
|
||||
</CollapseWrapperStyled>
|
||||
)
|
||||
})}
|
||||
</List>
|
||||
</div>
|
||||
{image !== undefined ? (
|
||||
<div
|
||||
className={classes.background}
|
||||
style={{ backgroundImage: "url(" + image + ")" }}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Sidebar.propTypes = {
|
||||
classes: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default withStyles(sidebarStyle)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(Sidebar)
|
||||
);
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import CheckboxAndRadioWrapper from "components/widgets/CheckboxAndRadioWrapper";
|
||||
import CollapseWrapperStyled from "components/widgets/CollapseWrapperStyled";
|
||||
|
||||
const elements = [
|
||||
{
|
||||
@@ -54,13 +55,12 @@ const elements = [
|
||||
class KuceFilter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Dodatno za kuce</span>
|
||||
<CollapseWrapperStyled componentName="Dodatno za kuce">
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="dodatno-za-kuce"
|
||||
elements={elements}
|
||||
/>
|
||||
</div>
|
||||
</CollapseWrapperStyled>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import React from "react";
|
||||
import CheckboxAndRadioWrapper from "components/widgets/CheckboxAndRadioWrapper";
|
||||
import CollapseWrapperStyled from "components/widgets/CollapseWrapperStyled";
|
||||
|
||||
const elements = [
|
||||
{
|
||||
@@ -61,13 +62,12 @@ const elements = [
|
||||
class StanoviFilter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Dodatno za stan</span>
|
||||
<CollapseWrapperStyled componentName="Dodatno za stan">
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="dodatno-za-stan"
|
||||
elements={elements}
|
||||
/>
|
||||
</div>
|
||||
</CollapseWrapperStyled>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,21 +2,49 @@ import React from "react";
|
||||
import * as Filters from "./AllFiltersDefined";
|
||||
import CheckboxAndRadioWrapper from "components/widgets/CheckboxAndRadioWrapper";
|
||||
import SelectDisplayCheckboxWrapper from "components/widgets/SelectDisplayCheckboxWrapper";
|
||||
import CollapseWrapperStyled from "components/widgets/CollapseWrapperStyled";
|
||||
import RangeWrapper from "components/widgets/RangeWrapper";
|
||||
import SelectWrapper from "components/widgets/SelectWrapper";
|
||||
import DropDownWrapper from "components/widgets/DropDownWrapper";
|
||||
|
||||
class NekretnineFilter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="vrsta"
|
||||
elements={Filters.vrstaElements}
|
||||
/>
|
||||
<SelectWrapper {...Filters.lokacijaOptions} />
|
||||
<SelectDisplayCheckboxWrapper {...Filters.gradoviOptions} />
|
||||
<RangeWrapper {...Filters.cijenaRangeOptions} optionName="cijena" />
|
||||
<RangeWrapper {...Filters.velicinaRangeOptions} optionName="velicina" />
|
||||
{[
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="Vrsta"
|
||||
elements={Filters.vrstaElements}
|
||||
/>,
|
||||
|
||||
<DropDownWrapper
|
||||
componentName="Lokacija"
|
||||
{...Filters.lokacijaOptions}
|
||||
/>,
|
||||
|
||||
<SelectDisplayCheckboxWrapper
|
||||
componentName="Grad"
|
||||
{...Filters.gradoviOptions}
|
||||
/>,
|
||||
|
||||
<RangeWrapper
|
||||
componentName="Cijena"
|
||||
{...Filters.cijenaRangeOptions}
|
||||
optionName="cijena"
|
||||
/>,
|
||||
|
||||
<RangeWrapper
|
||||
componentName="Velicina"
|
||||
{...Filters.velicinaRangeOptions}
|
||||
optionName="velicina"
|
||||
/>
|
||||
].map(comp => (
|
||||
<CollapseWrapperStyled
|
||||
key={comp.props.componentName}
|
||||
componentName={comp.props.componentName}
|
||||
>
|
||||
{comp}
|
||||
</CollapseWrapperStyled>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,26 +2,54 @@ import React from "react";
|
||||
import * as Filters from "./AllFiltersDefined";
|
||||
import CheckboxAndRadioWrapper from "components/widgets/CheckboxAndRadioWrapper";
|
||||
import RangeWrapper from "components/widgets/RangeWrapper";
|
||||
import SelectWrapper from "components/widgets/SelectWrapper";
|
||||
import CollapseWrapperStyled from "components/widgets/CollapseWrapperStyled";
|
||||
import DropDownWrapper from "components/widgets/DropDownWrapper";
|
||||
|
||||
class VozilaFilter extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="stanje"
|
||||
elements={Filters.stanjeElements}
|
||||
/>
|
||||
<SelectWrapper {...Filters.proizvodacOptions} />
|
||||
<RangeWrapper {...Filters.cijenaRangeOptions} />
|
||||
<SelectWrapper {...Filters.lokacijaOptions} />
|
||||
<RangeWrapper {...Filters.godisteRangeOptions} />
|
||||
<SelectWrapper {...Filters.kilometrazaOptions.kilometraMin} />
|
||||
<SelectWrapper {...Filters.kilometrazaOptions.kilometraMax} />
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="gorivo"
|
||||
elements={Filters.gorivoElements}
|
||||
/>
|
||||
{[
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="Stanje"
|
||||
elements={Filters.stanjeElements}
|
||||
/>,
|
||||
<DropDownWrapper
|
||||
componentName="Proizvodac"
|
||||
{...Filters.proizvodacOptions}
|
||||
/>,
|
||||
<RangeWrapper
|
||||
componentName="Cijena"
|
||||
{...Filters.cijenaRangeOptions}
|
||||
/>,
|
||||
<DropDownWrapper
|
||||
componentName="Lokacija"
|
||||
{...Filters.lokacijaOptions}
|
||||
/>,
|
||||
<RangeWrapper
|
||||
componentName="Godiste"
|
||||
{...Filters.godisteRangeOptions}
|
||||
/>,
|
||||
<DropDownWrapper
|
||||
componentName="Min kilometraza"
|
||||
{...Filters.kilometrazaOptions.kilometraMin}
|
||||
/>,
|
||||
<DropDownWrapper
|
||||
componentName="Max kilometraza"
|
||||
{...Filters.kilometrazaOptions.kilometraMax}
|
||||
/>,
|
||||
<CheckboxAndRadioWrapper
|
||||
componentName="Gorivo"
|
||||
elements={Filters.gorivoElements}
|
||||
/>
|
||||
].map(comp => (
|
||||
<CollapseWrapperStyled
|
||||
key={comp.props.componentName}
|
||||
componentName={comp.props.componentName}
|
||||
>
|
||||
{comp}
|
||||
</CollapseWrapperStyled>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
.item {
|
||||
display: grid;
|
||||
border: solid #877ad2 1px;
|
||||
border-radius: 10px;
|
||||
max-width: 360px;
|
||||
min-height: 300px;
|
||||
border: solid #ffc600 1px;
|
||||
border-radius: 5px;
|
||||
max-width: 200px;
|
||||
min-height: 150px;
|
||||
grid-template-areas:
|
||||
"image"
|
||||
"title";
|
||||
margin: 3%;
|
||||
background-color: #dbdbd7;
|
||||
background-color: #272727;
|
||||
justify-items: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.item > a > img {
|
||||
width: 70%;
|
||||
height: 60%;
|
||||
max-height: 200px;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
min-height: 100px !important;
|
||||
min-width: 150px !important;
|
||||
grid-area: image;
|
||||
padding: 8% 8% 0 8%;
|
||||
}
|
||||
.item > a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.basic-info {
|
||||
grid-area: title;
|
||||
width: 85%;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.basic-info > h3 {
|
||||
font-size: 90%;
|
||||
margin: 5%;
|
||||
margin-bottom: 0px;
|
||||
color: #332390;
|
||||
color: #ffc600;
|
||||
padding-bottom: 10px;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
margin-top: 8%;
|
||||
display: grid;
|
||||
grid-gap: 5px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
grid-template-rows: repeat(2, 320px);
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
@@ -19,11 +19,7 @@ class ItemContainer extends Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<div className="items-list">{this.renderItems()}</div>
|
||||
</div>
|
||||
);
|
||||
return <div className="items-list">{this.renderItems()}</div>;
|
||||
}
|
||||
}
|
||||
export default connect(mapStateToProps)(ItemContainer);
|
||||
|
||||
@@ -2,14 +2,13 @@ import React from "react";
|
||||
import NekretnineFilter from "components/filters/NekretnineFilter/index";
|
||||
import KuceFilter from "components/filters/NekretnineFilter/KuceFilter/index";
|
||||
class Kuce extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Kuce</span>
|
||||
<NekretnineFilter />
|
||||
<KuceFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<NekretnineFilter />
|
||||
<KuceFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Kuce;
|
||||
|
||||
@@ -3,14 +3,13 @@ import NekretnineFilter from "components/filters/NekretnineFilter/index";
|
||||
import StanoviFilter from "components/filters/NekretnineFilter/StanoviFilter/index";
|
||||
|
||||
class Stanovi extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Stanovi</span>
|
||||
<NekretnineFilter />
|
||||
<StanoviFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<NekretnineFilter />
|
||||
<StanoviFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Stanovi;
|
||||
|
||||
@@ -2,13 +2,12 @@ import React from "react";
|
||||
import VozilaFilter from "components/filters/VozilaFilter/index";
|
||||
|
||||
class Automobili extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Auto</span>
|
||||
<VozilaFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<VozilaFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Automobili;
|
||||
|
||||
@@ -2,13 +2,12 @@ import React from "react";
|
||||
import VozilaFilter from "components/filters/VozilaFilter/index";
|
||||
|
||||
class Motocikli extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<span>Motocikli</span>
|
||||
<VozilaFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<VozilaFilter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default Motocikli;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import React from "react";
|
||||
import { optionchangewrapper } from "utils/optionchangewrapper";
|
||||
import Checkbox from "@material-ui/core/Checkbox";
|
||||
import Radio from "@material-ui/core/Radio";
|
||||
import "assets/checkboxAndRadioStyle.css";
|
||||
|
||||
class CheckboxAndRadioWrapper extends React.Component {
|
||||
optionChange = (option, optionName, type) => {
|
||||
@@ -22,26 +25,33 @@ class CheckboxAndRadioWrapper extends React.Component {
|
||||
renderElements = (elements, componentName) => {
|
||||
return elements.map(({ type, value, name, optionName } = {}) => (
|
||||
<label key={name + type}>
|
||||
<input
|
||||
name={type === "radio" ? `${componentName}-radio` : ""}
|
||||
type={type}
|
||||
value={value}
|
||||
checked={this.isChecked(type, value, optionName)}
|
||||
onChange={option => this.optionChange(option, optionName, type)}
|
||||
/>
|
||||
{name}
|
||||
{type === "radio" ? (
|
||||
<Radio
|
||||
className="radio-style"
|
||||
name={type === "radio" ? `${componentName}-radio` : ""}
|
||||
type={type}
|
||||
value={value}
|
||||
checked={this.isChecked(type, value, optionName)}
|
||||
onChange={option => this.optionChange(option, optionName, type)}
|
||||
/>
|
||||
) : (
|
||||
<Checkbox
|
||||
className="checkbox-style"
|
||||
type={type}
|
||||
value={value}
|
||||
checked={this.isChecked(type, value, optionName)}
|
||||
onChange={option => this.optionChange(option, optionName, type)}
|
||||
/>
|
||||
)}
|
||||
<span className="label-style">{name}</span>
|
||||
<br />
|
||||
</label>
|
||||
));
|
||||
};
|
||||
|
||||
render() {
|
||||
const { elements, componentName } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<span>{componentName}</span>
|
||||
{this.renderElements(elements, componentName)}
|
||||
</div>
|
||||
);
|
||||
return <div>{this.renderElements(elements, componentName)}</div>;
|
||||
}
|
||||
}
|
||||
export default optionchangewrapper(CheckboxAndRadioWrapper);
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { OPTION_EXPAND_CHANGE } from "constants/actionTypes";
|
||||
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import sidebarStyle from "assets/sidebarStyle.js";
|
||||
import Collapse from "@material-ui/core/Collapse";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import ExpandLess from "@material-ui/icons/ExpandLess";
|
||||
import ExpandMore from "@material-ui/icons/ExpandMore";
|
||||
import Dashboard from "@material-ui/icons/Dashboard";
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
uiexpand: state.uiexpand
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => ({
|
||||
onUIExpandChanged: uiExpandOption =>
|
||||
dispatch({ type: OPTION_EXPAND_CHANGE, ...uiExpandOption })
|
||||
});
|
||||
|
||||
class CollapseWrapperStyled extends React.Component {
|
||||
handleClick = componentName => {
|
||||
this.props.onUIExpandChanged({
|
||||
controlName: componentName,
|
||||
value: !this.props.uiexpand[componentName]
|
||||
});
|
||||
};
|
||||
|
||||
isopen = componentName => this.props.uiexpand[componentName];
|
||||
render() {
|
||||
let { classes, componentName } = this.props;
|
||||
return (
|
||||
<div>
|
||||
<ListItem
|
||||
className={classes.whiteText}
|
||||
onClick={() => this.handleClick(componentName)}
|
||||
>
|
||||
<ListItemIcon className={classes.whiteText}>
|
||||
<Dashboard />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.whiteText}
|
||||
inset
|
||||
primary={componentName}
|
||||
disableTypography={true}
|
||||
/>
|
||||
{this.isopen(componentName) ? <ExpandLess /> : <ExpandMore />}
|
||||
</ListItem>
|
||||
<Collapse
|
||||
className={classes.subOptionIndent}
|
||||
in={this.isopen(componentName)}
|
||||
timeout="auto"
|
||||
unmountOnExit
|
||||
>
|
||||
{this.props.children}
|
||||
</Collapse>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default withStyles(sidebarStyle)(
|
||||
connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(CollapseWrapperStyled)
|
||||
);
|
||||
@@ -1,8 +1,15 @@
|
||||
import React from "react";
|
||||
import Select from "react-select";
|
||||
import { subcategorywrapper } from "utils/subcategorywrapper";
|
||||
import { hoc } from "utils/helpers";
|
||||
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import sidebarStyle from "assets/sidebarStyle.js";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import StarBorder from "@material-ui/icons/StarBorder";
|
||||
|
||||
class DeepCategoryWrapper extends React.Component {
|
||||
handleOptionChange = selectedOption => {
|
||||
const { depth, onSubCategoryChanged } = this.props;
|
||||
@@ -10,21 +17,45 @@ class DeepCategoryWrapper extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { options, depth, childrenComponents } = this.props;
|
||||
const { options, depth, childrenComponents, classes } = this.props;
|
||||
const {
|
||||
subcategory: { [depth]: deepSubCategory }
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
value={deepSubCategory || null}
|
||||
onChange={this.handleOptionChange}
|
||||
options={options}
|
||||
/>
|
||||
<List disablePadding>
|
||||
{options.map(({ label, value }, index) => (
|
||||
<ListItem
|
||||
onClick={() => this.handleOptionChange({ label, value })}
|
||||
className={
|
||||
classes.nested +
|
||||
" " +
|
||||
classes.collapsedItemStyle +
|
||||
" " +
|
||||
(deepSubCategory && deepSubCategory.value === value
|
||||
? classes.checkedItem
|
||||
: "")
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
<ListItemIcon className={classes.whiteText}>
|
||||
<StarBorder />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.whiteText}
|
||||
primary={label}
|
||||
disableTypography={true}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
|
||||
{hoc(deepSubCategory && deepSubCategory.value, childrenComponents)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default subcategorywrapper(DeepCategoryWrapper);
|
||||
export default withStyles(sidebarStyle)(
|
||||
subcategorywrapper(DeepCategoryWrapper)
|
||||
);
|
||||
|
||||
54
frontend-react/src/components/widgets/DropDownWrapper.js
Normal file
54
frontend-react/src/components/widgets/DropDownWrapper.js
Normal file
@@ -0,0 +1,54 @@
|
||||
import React from "react";
|
||||
import { optionchangewrapper } from "utils/optionchangewrapper";
|
||||
|
||||
import withStyles from "@material-ui/core/styles/withStyles";
|
||||
import List from "@material-ui/core/List";
|
||||
import ListItem from "@material-ui/core/ListItem";
|
||||
import ListItemIcon from "@material-ui/core/ListItemIcon";
|
||||
import ListItemText from "@material-ui/core/ListItemText";
|
||||
import sidebarStyle from "assets/sidebarStyle.js";
|
||||
import StarBorder from "@material-ui/icons/StarBorder";
|
||||
|
||||
class DropdownWrapper extends React.Component {
|
||||
handleOptionChange = selectedOption => {
|
||||
const { onOptionChanged, optionName } = this.props;
|
||||
onOptionChanged({
|
||||
optionName,
|
||||
optionValue: selectedOption
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let { value, options, choices, classes } = this.props;
|
||||
let optionName = value;
|
||||
return (
|
||||
<List disablePadding>
|
||||
{choices.map(({ label, value }, index) => (
|
||||
<ListItem
|
||||
onClick={() => this.handleOptionChange({ label, value })}
|
||||
className={
|
||||
classes.nested +
|
||||
" " +
|
||||
classes.collapsedItemStyle +
|
||||
" " +
|
||||
(options[optionName] && options[optionName].value === value
|
||||
? classes.checkedItem
|
||||
: "")
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
<ListItemIcon className={classes.whiteText}>
|
||||
<StarBorder />
|
||||
</ListItemIcon>
|
||||
<ListItemText
|
||||
className={classes.whiteText}
|
||||
primary={label}
|
||||
disableTypography={true}
|
||||
/>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
}
|
||||
}
|
||||
export default withStyles(sidebarStyle)(optionchangewrapper(DropdownWrapper));
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from "react";
|
||||
import { Range } from "rc-slider";
|
||||
import { optionchangewrapper } from "utils/optionchangewrapper";
|
||||
import "assets/rangeStyle.css";
|
||||
import "rc-slider/assets/index.css";
|
||||
import Input from "@material-ui/core/Input";
|
||||
|
||||
class RangeWrapper extends React.Component {
|
||||
sendAction = (optionName, optionValue) => {
|
||||
@@ -39,14 +41,24 @@ class RangeWrapper extends React.Component {
|
||||
step={step}
|
||||
onAfterChange={this.handleRangeChange}
|
||||
/>
|
||||
<input
|
||||
ref={node => {
|
||||
<Input
|
||||
placeholder="Min"
|
||||
className="input-style"
|
||||
inputProps={{
|
||||
"aria-label": "Min"
|
||||
}}
|
||||
inputRef={node => {
|
||||
this.inputMin = node;
|
||||
}}
|
||||
onChange={this.handleInputChange}
|
||||
/>
|
||||
<input
|
||||
ref={node => {
|
||||
<Input
|
||||
placeholder="Max"
|
||||
className="input-style"
|
||||
inputProps={{
|
||||
"aria-label": "Max"
|
||||
}}
|
||||
inputRef={node => {
|
||||
this.inputMax = node;
|
||||
}}
|
||||
onChange={this.handleInputChange}
|
||||
|
||||
@@ -5,3 +5,4 @@ export const ITEMS_CHANGED = "ITEMS_CHANGED";
|
||||
export const MODAL_CLOSE = "MODAL_CLOSE";
|
||||
export const MODAL_OPEN = " MODAL_OPEN";
|
||||
export const USER_DATA_CHANGED = "USER_DATA_CHANGED";
|
||||
export const OPTION_EXPAND_CHANGE = "OPTION_EXPAND_CHANGE";
|
||||
|
||||
@@ -4,9 +4,11 @@ import React from "react";
|
||||
import { store } from "./store";
|
||||
|
||||
import App from "./components/App";
|
||||
import CssBaseline from "@material-ui/core/CssBaseline";
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<CssBaseline />
|
||||
<App />
|
||||
</Provider>,
|
||||
document.getElementById("root")
|
||||
|
||||
@@ -4,6 +4,7 @@ import options from "./reducers/options";
|
||||
import items from "./reducers/items";
|
||||
import modal from "./reducers/modal";
|
||||
import userdata from "./reducers/userdata";
|
||||
import uiexpand from "./reducers/uiexpand";
|
||||
import { combineReducers } from "redux";
|
||||
|
||||
export default combineReducers({
|
||||
@@ -12,5 +13,6 @@ export default combineReducers({
|
||||
options,
|
||||
items,
|
||||
modal,
|
||||
userdata
|
||||
userdata,
|
||||
uiexpand
|
||||
});
|
||||
|
||||
18
frontend-react/src/reducers/uiexpand.js
Normal file
18
frontend-react/src/reducers/uiexpand.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import {
|
||||
OPTION_EXPAND_CHANGE,
|
||||
CATEGORY_SELECT,
|
||||
SUBCATEGORY_SELECT
|
||||
} from "constants/actionTypes";
|
||||
|
||||
export default (state = {}, action) => {
|
||||
switch (action.type) {
|
||||
case OPTION_EXPAND_CHANGE:
|
||||
return { ...state, [action.controlName]: action.value };
|
||||
case CATEGORY_SELECT:
|
||||
return {};
|
||||
case SUBCATEGORY_SELECT:
|
||||
return { Podkategorija: state["Podkategorija"] };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user