diff --git a/frontend-react/src/components/App.js b/frontend-react/src/components/App.js index d86d479..bf43794 100644 --- a/frontend-react/src/components/App.js +++ b/frontend-react/src/components/App.js @@ -2,7 +2,7 @@ import React from "react"; import Select from "react-select"; import { connect } from "react-redux"; import { CATEGORY_SELECT, ITEMS_CHANGED } from "constants/actionTypes"; -import { hoc } from "utils/hoc"; +import { hoc, areObjectEqual } from "utils/helpers"; import { createOlxLink } from "utils/createOlxLink"; import axios from "axios"; @@ -29,21 +29,43 @@ const mapDispatchToProps = dispatch => ({ onItemsChanged: items => dispatch({ type: ITEMS_CHANGED, items }) }); +let lastUpdateTime = null; +let interval = null; class App extends React.Component { + componentDidMount() { + interval = setInterval(() => { + if (lastUpdateTime && Date.now() - lastUpdateTime > 2000) { + const { category, options, subcategory, onItemsChanged } = this.props; + let url = createOlxLink(category, subcategory, options); + url = encodeURI(url); + if (url) { + axios + .get(`/api/${url}`) + .then(response => onItemsChanged(response.data)) + .catch(error => console.log(error)); + } + lastUpdateTime = null; + } + }, 1000); + } + + componentWillUnmount() { + clearInterval(interval); + } + componentWillReceiveProps(newProps) { + const { subcategory, category, options } = this.props; + if ( + newProps.subcategory !== subcategory || + newProps.category !== category || + !areObjectEqual(newProps.options, options) + ) { + lastUpdateTime = Date.now(); + } + } handleChange = selectedOption => { this.props.onCategoryChanged(selectedOption); }; - getDataFromOlx = () => { - const { category, options, subcategory, onItemsChanged } = this.props; - let url = createOlxLink(category, subcategory, options); - url = encodeURI(url); - axios - .get(`/api/${url}`) - .then(response => onItemsChanged(response.data)) - .catch(error => console.log(error)); - }; - render() { const { category } = this.props; @@ -58,7 +80,6 @@ class App extends React.Component { Vozila: , Nekretnine: })} - ); diff --git a/frontend-react/src/components/categories/Nekretnine.js b/frontend-react/src/components/categories/Nekretnine.js index 0ad3c02..41721e4 100644 --- a/frontend-react/src/components/categories/Nekretnine.js +++ b/frontend-react/src/components/categories/Nekretnine.js @@ -1,15 +1,12 @@ import React from "react"; import Select from "react-select"; import { subcategorywrapper } from "utils/subcategorywrapper"; -import { hoc } from "utils/hoc"; +import { hoc } from "utils/helpers"; import Stanovi from "../subcategories/nekretnine/Stanovi"; import Kuce from "../subcategories/nekretnine/Kuce"; -const options = [ - { value: "Stanovi", label: "Stanovi" }, - { value: "Kuce", label: "Kuce" } -]; +const options = [{ value: 23, label: "Stanovi" }, { value: 24, label: "Kuce" }]; class Nekretnine extends React.Component { handleChange = selectedOption => { @@ -27,8 +24,8 @@ class Nekretnine extends React.Component { options={options} /> {hoc(subcategory && subcategory.value, { - Stanovi: , - Kuce: + 23: , + 24: })} ); diff --git a/frontend-react/src/components/categories/Vozila.js b/frontend-react/src/components/categories/Vozila.js index 9fddd0f..5302c7b 100644 --- a/frontend-react/src/components/categories/Vozila.js +++ b/frontend-react/src/components/categories/Vozila.js @@ -3,35 +3,35 @@ import Select from "react-select"; import Automobili from "../subcategories/vozila/Automobili"; import Motocikli from "../subcategories/vozila/Motocikli"; import { subcategorywrapper } from "utils/subcategorywrapper"; -import { hoc } from "utils/hoc"; +import { hoc } from "utils/helpers"; const options = [ - { value: "Automobili", label: "Automobili" }, - { value: "Motocikli", label: "Motocikli" } + { value: 18, label: "Automobili" }, + { value: 21, label: "Motocikli" } ]; class Vozila extends React.Component { - handleChange = selectedOption => { - this.props.onSubCategoryChanged(selectedOption); - }; + handleChange = selectedOption => { + this.props.onSubCategoryChanged(selectedOption); + }; - render() { - const { subcategory } = this.props; + render() { + const { subcategory } = this.props; - return ( -
- + {hoc(subcategory && subcategory.value, { + 18: , + 21: + })} +
+ ); + } } export default subcategorywrapper(Vozila); diff --git a/frontend-react/src/components/filters/NekretnineFilter/Cijena.js b/frontend-react/src/components/filters/NekretnineFilter/Cijena.js index 5ee7336..8363a2d 100644 --- a/frontend-react/src/components/filters/NekretnineFilter/Cijena.js +++ b/frontend-react/src/components/filters/NekretnineFilter/Cijena.js @@ -2,5 +2,6 @@ export const rangeOptions = { min: 0, max: 100000, defaultValues: [0, 100000], - step: 100 + step: 100, + optionNames: ["od", "do"] }; diff --git a/frontend-react/src/components/filters/NekretnineFilter/KuceFilter/index.js b/frontend-react/src/components/filters/NekretnineFilter/KuceFilter/index.js index 1ae5fc6..1abbeb3 100644 --- a/frontend-react/src/components/filters/NekretnineFilter/KuceFilter/index.js +++ b/frontend-react/src/components/filters/NekretnineFilter/KuceFilter/index.js @@ -5,42 +5,50 @@ const elements = [ { type: "checkbox", name: "Uknjizeno", - optionName: "uknjizeno" + optionName: "uknjizeno-zk_checkbox", + value: "on" }, { type: "checkbox", name: "Namjesteno", - optionName: "namjesteno" + optionName: "namjestena_checkbox", + value: "on" }, { type: "checkbox", name: "Nedavno adaptirano", - optionName: "nedavno_adaptirano" + optionName: "nedavno-adaptirana_checkbox", + value: "on" }, { type: "checkbox", name: "Garaza", - optionName: "garaza" + optionName: "gara-a_checkbox", + value: "on" }, { type: "checkbox", name: "Balkon", - optionName: "balkon" + optionName: "balkon_checkbox", + value: "on" }, { type: "checkbox", name: "Voda", - optionName: "voda" + optionName: "voda_checkbox", + value: "on" }, { type: "checkbox", name: "Plin", - optionName: "plin" + optionName: "plin_checkbox", + value: "on" }, { type: "checkbox", name: "Bazen", - optionName: "bazen" + optionName: "bazen_checkbox", + value: "on" } ]; class KuceFilter extends React.Component { diff --git a/frontend-react/src/components/filters/NekretnineFilter/StanoviFilter/index.js b/frontend-react/src/components/filters/NekretnineFilter/StanoviFilter/index.js index 6623663..bf9cebb 100644 --- a/frontend-react/src/components/filters/NekretnineFilter/StanoviFilter/index.js +++ b/frontend-react/src/components/filters/NekretnineFilter/StanoviFilter/index.js @@ -5,47 +5,56 @@ const elements = [ { type: "checkbox", name: "Novogradnja", - optionName: "novogradnja" + optionName: "novogradnja_checkbox", + value: "on" }, { type: "checkbox", name: "Namjesten", - optionName: "namjesten" + optionName: "namjesten_checkbox", + value: "on" }, { type: "checkbox", name: "Nedavno adaptiran", - optionName: "Nedavno_adaptiran" + optionName: "nedavno-adaptiran_checkbox", + value: "on" }, { type: "checkbox", name: "Uknjizeno", - optionName: "uknjizeno" + optionName: "uknjizeno-zk_checkbox", + value: "on" }, { type: "checkbox", name: "Lift", - optionName: "lift" + optionName: "lift_checkbox", + value: "on" }, { type: "checkbox", name: "Balkon", - optionName: "balkon" + optionName: "balkon_checkbox", + value: "on" }, { type: "checkbox", name: "Parking", - optionName: "parking" + optionName: "parking_checkbox", + value: "on" }, { type: "checkbox", name: "Plin", - optionName: "plin" + optionName: "plin_checkbox", + value: "on" }, { type: "checkbox", name: "kablovska", - optionName: "kablovska" + optionName: "kablovska-tv_checkbox", + value: "on" } ]; diff --git a/frontend-react/src/components/filters/NekretnineFilter/Velicina.js b/frontend-react/src/components/filters/NekretnineFilter/Velicina.js index ab3a6f3..5e9b162 100644 --- a/frontend-react/src/components/filters/NekretnineFilter/Velicina.js +++ b/frontend-react/src/components/filters/NekretnineFilter/Velicina.js @@ -2,5 +2,6 @@ export const rangeOptions = { min: 0, max: 1000, defaultValues: [0, new Date().getFullYear()], - step: 1 + step: 1, + optionNames: ["kvadrata_min", "kvadrata_max"] }; diff --git a/frontend-react/src/components/filters/VozilaFilter/Cijena.js b/frontend-react/src/components/filters/VozilaFilter/Cijena.js index 5ee7336..8363a2d 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Cijena.js +++ b/frontend-react/src/components/filters/VozilaFilter/Cijena.js @@ -2,5 +2,6 @@ export const rangeOptions = { min: 0, max: 100000, defaultValues: [0, 100000], - step: 100 + step: 100, + optionNames: ["od", "do"] }; diff --git a/frontend-react/src/components/filters/VozilaFilter/Godiste.js b/frontend-react/src/components/filters/VozilaFilter/Godiste.js index d0b0c3f..c61253c 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Godiste.js +++ b/frontend-react/src/components/filters/VozilaFilter/Godiste.js @@ -2,5 +2,6 @@ export const rangeOptions = { min: 1960, max: new Date().getFullYear(), defaultValues: [1960, new Date().getFullYear()], - step: 1 + step: 1, + optionNames: ["godiste_min", "godiste_max"] }; diff --git a/frontend-react/src/components/filters/VozilaFilter/Gorivo.js b/frontend-react/src/components/filters/VozilaFilter/Gorivo.js index aea510f..3ecae73 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Gorivo.js +++ b/frontend-react/src/components/filters/VozilaFilter/Gorivo.js @@ -2,26 +2,31 @@ export const elements = [ { name: "Dizel", optionName: "gorivo_select_dizel", - type: "checkbox" + type: "checkbox", + value: "Dizel" }, { name: "Benzin", optionName: "gorivo_select_benzin", - type: "checkbox" + type: "checkbox", + value: "Benzin" }, { name: "Plin", optionName: "gorivo_select_plin", - type: "checkbox" + type: "checkbox", + value: "Plin" }, { name: "Hibrid", optionName: "gorivo_select_hibrid", - type: "checkbox" + type: "checkbox", + value: "Hibrid" }, { name: "Elektro", optionName: "gorivo_select_elektro", - type: "checkbox" + type: "checkbox", + value: "Elektro" } ]; diff --git a/frontend-react/src/components/filters/VozilaFilter/Kilometraza.js b/frontend-react/src/components/filters/VozilaFilter/Kilometraza.js index 226ce8f..38a0a19 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Kilometraza.js +++ b/frontend-react/src/components/filters/VozilaFilter/Kilometraza.js @@ -1,15 +1,15 @@ export const kilometrazaOptions = { kilometraMin: { choices: [{ value: 5000, label: "5000" }, { value: 10000, label: "10000" }], - value: "kilometrazaMin", - optionName: "kilometrazaMin" + value: "kilometra-a_min", + optionName: "kilometra-a_min" }, kilometraMax: { choices: [ { value: 15000, label: "15000" }, { value: 200000, label: "200000" } ], - value: "kilometrazaMax", - optionName: "kilometrazaMax" + value: "kilometra-a_max", + optionName: "kilometra-a_max" } }; diff --git a/frontend-react/src/components/filters/VozilaFilter/Proizvodac.js b/frontend-react/src/components/filters/VozilaFilter/Proizvodac.js index 61835ed..948f227 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Proizvodac.js +++ b/frontend-react/src/components/filters/VozilaFilter/Proizvodac.js @@ -1,5 +1,5 @@ export const proizvodacOptions = { choices: [{ value: "1900", label: "Audi" }, { value: "9000", label: "Ford" }], - value: "proizvodac", - optionName: "proizvodac" + value: "v_b", + optionName: "v_b" }; diff --git a/frontend-react/src/components/filters/VozilaFilter/Stanje.js b/frontend-react/src/components/filters/VozilaFilter/Stanje.js index 1bab5e4..25ea375 100644 --- a/frontend-react/src/components/filters/VozilaFilter/Stanje.js +++ b/frontend-react/src/components/filters/VozilaFilter/Stanje.js @@ -20,6 +20,7 @@ export const elements = [ { type: "checkbox", name: "Udarena vozila", - optionName: "udaren_checkbox" + optionName: "udaren_checkbox", + value: "on" } ]; diff --git a/frontend-react/src/components/filters/VozilaFilter/index.js b/frontend-react/src/components/filters/VozilaFilter/index.js index fcb5d7e..64eeb28 100644 --- a/frontend-react/src/components/filters/VozilaFilter/index.js +++ b/frontend-react/src/components/filters/VozilaFilter/index.js @@ -19,9 +19,9 @@ class VozilaFilter extends React.Component { elements={Stanje.elements} /> - + - + { const optionTypePicker = { radio: option.target.value, - checkbox: option.target.checked + checkbox: option.target.checked ? option.target.value : false }; const { onOptionChanged } = this.props; onOptionChanged({ @@ -15,10 +15,9 @@ class CheckboxAndRadioWrapper extends React.Component { }; isChecked = (type, value, optionName) => { const { options } = this.props; - return type === "checkbox" - ? value - : options.hasOwnProperty(optionName) && - options[optionName] === String(value); + return options.hasOwnProperty(optionName) && type === "checkbox" + ? options[optionName] + : options[optionName] === String(value); }; renderElements = (elements, componentName) => { return elements.map(({ type, value, name, optionName } = {}) => ( diff --git a/frontend-react/src/components/widgets/RangeWrapper.js b/frontend-react/src/components/widgets/RangeWrapper.js index 576ad93..3f4cf18 100644 --- a/frontend-react/src/components/widgets/RangeWrapper.js +++ b/frontend-react/src/components/widgets/RangeWrapper.js @@ -4,22 +4,28 @@ import { optionchangewrapper } from "utils/optionchangewrapper"; import "rc-slider/assets/index.css"; class RangeWrapper extends React.Component { + sendAction = (optionName, optionValue) => { + this.props.onOptionChanged({ + optionName, + optionValue + }); + }; handleRangeChange = ([min, max] = this.props.defaultValues) => { this.inputMin.value = min; this.inputMax.value = max; - const { onOptionChanged, optionName } = this.props; - onOptionChanged({ - optionName, - optionValue: [min, max] - }); + const { optionNames } = this.props; + const optionValues = [min, max]; + optionNames.forEach((optionName, index) => + this.sendAction(optionName, optionValues[index]) + ); }; handleInputChange = () => { - const { onOptionChanged, optionName } = this.props; - onOptionChanged({ - optionName, - optionValue: [this.inputMin.value, this.inputMax.value] - }); + const { optionNames } = this.props; + const optionValues = [this.inputMin.value, this.inputMax.value]; + optionNames.forEach((optionName, index) => + this.sendAction(optionName, optionValues[index]) + ); }; render() { diff --git a/frontend-react/src/utils/createOlxLink.js b/frontend-react/src/utils/createOlxLink.js index 51578fc..3c284da 100644 --- a/frontend-react/src/utils/createOlxLink.js +++ b/frontend-react/src/utils/createOlxLink.js @@ -1,63 +1,15 @@ -/*category: {value: "Vozila", label: "Vozila"} -options: -cijena: (2) [6500, 70500] -godiste: (2) [2004, 2017] -gorivo_select_benzin: true -gorivo_select_dizel: true -kanton: {value: "9", label: "Sarajevo"} -kilometrazaMax: {value: 20000, label: "20000"} -kilometrazaMin: {value: 5000, label: "5000"} -proizvodac: {value: "1900", label: "Audi"} -stanje: "" -subcategory: {value: "Automobili", label: "Automobili"} +const isObject = obj => obj === Object(obj); +const mapOptionToLink = (options, option) => + options[option] !== false + ? `${option}=${ + isObject(options[option]) ? options[option].value : options[option] + }&` + : ""; - -https://www.olx.ba/pretraga? -kategorija=18&stanje=&v_b=1900 -&od=6500&do=70500 -&kanton=9& -godiste_min=2004&godiste_max=2017 -&kilometra-a_min=5000&kilometra-a_max=50000 -&gorivo_select_dizel=Dizel&gorivo_select_benzin=Benzin - -{ - "Automobili": 18, - "v_b": "proizvodac", - -}*/ -function AutomobiliLinkCreator(options) { - const [od, do_] = options.cijena; - const [godiste_min, godiste_max] = options.godiste; - const goriva = [ - "gorivo_select_benzin", - "gorivo_select_dizel", - "gorivo_select_plin", - "gorivo_select_hibrid", - "gorivo_selector_elektro" - ] - .filter(gorivo => options.hasOwnProperty(gorivo)) - .reduce( - (izborGoriva, gorivo) => - izborGoriva + - "" + - options[gorivo] + - "=" + - options[gorivo] + - "&", - "" - ); - return `kategorija=18&stanje=${options.stanje}&v_b=${ - options.proizvodac.value - }&od=${od}&do=${do_}&kanton=${ - options.kanton.value - }&godiste_min=${godiste_min}&godiste_max=${godiste_max}&kilometra-a_min=${ - options.kilometrazaMin.value - }&kilometra-a_max=${options.kilometrazaMax.value}&${goriva}`; -} -const mappingFunctios = { - Automobili: AutomobiliLinkCreator -}; - -export const createOlxLink = (category, subcategory, options) => { - return mappingFunctios[subcategory.value](options); -}; +export const createOlxLink = (category, subcategory, options) => + subcategory.value + ? Object.keys(options).reduce( + (link, option) => link + mapOptionToLink(options, option), + `kategorija=${subcategory.value}&` + ) + : ""; diff --git a/frontend-react/src/utils/helpers.js b/frontend-react/src/utils/helpers.js new file mode 100644 index 0000000..d1e7e61 --- /dev/null +++ b/frontend-react/src/utils/helpers.js @@ -0,0 +1,11 @@ +export const hoc = (option, componentList) => componentList[option] || null; +export const areObjectEqual = function checkEquality(objectA, objectB) { + return ( + Object.keys(objectA).length === Object.keys(objectB).length && + Object.keys(objectA).every(property => + objectA[property] === Object(objectA[property]) + ? checkEquality(objectA[property], objectB[property]) + : objectA[property] === objectB[property] + ) + ); +}; diff --git a/frontend-react/src/utils/hoc.js b/frontend-react/src/utils/hoc.js deleted file mode 100644 index c191069..0000000 --- a/frontend-react/src/utils/hoc.js +++ /dev/null @@ -1 +0,0 @@ -export const hoc = (option, componentList) => componentList[option] || null;