From 0d99c97116ae66a4e7ecb616f5351e5a0c50610a Mon Sep 17 00:00:00 2001 From: Miu Razvan Date: Thu, 13 Aug 2020 21:14:36 +0300 Subject: [PATCH] Implemented FiltersBlock --- .../manage/Blocks/FiltersBlock/View.jsx | 648 +++++++++++++++--- .../manage/Blocks/FiltersBlock/style.css | 47 +- theme/site/globals/site.overrides | 13 + 3 files changed, 586 insertions(+), 122 deletions(-) diff --git a/src/components/manage/Blocks/FiltersBlock/View.jsx b/src/components/manage/Blocks/FiltersBlock/View.jsx index 9968046..bce717a 100644 --- a/src/components/manage/Blocks/FiltersBlock/View.jsx +++ b/src/components/manage/Blocks/FiltersBlock/View.jsx @@ -3,90 +3,360 @@ import React, { useState, useEffect } from 'react'; import { useHistory } from 'react-router-dom'; import { compose } from 'redux'; import { connect } from 'react-redux'; -import { Button, Header, Image, Modal, Select, Input } from 'semantic-ui-react'; +import { + Button, + Header, + Image, + Modal, + Select, + Input, + Radio, +} from 'semantic-ui-react'; +import { Icon } from '@plone/volto/components'; import { setQueryParam } from 'volto-datablocks/actions'; +import { settings } from '~/config'; import _uniqueId from 'lodash/uniqueId'; import axios from 'axios'; + +import circlePlus from '@plone/volto/icons/circle-plus.svg'; +import circleMinus from '@plone/volto/icons/circle-minus.svg'; +import clear from '@plone/volto/icons/clear.svg'; + import './style.css'; + +let nrOfRequests = 0; +const makeUrl = (providerUrl, url) => { + return encodeURI(providerUrl + `?query=${url}`); +}; + const View = ({ content, ...props }) => { + const providerUrl = settings.providerUrl; + const { search } = props.discodata_query; const [state, setState] = useState({ open: false, filters: {}, filtersMeta: {}, + filtersMetaOrder: [ + 'industries', + 'countries', + 'regions', + 'town_village', + 'pollutant_groups', + 'pollutants', + 'reporting_years', + 'bat_conclusions', + ], + mounted: false, + firstLoad: false, }); const title = props.data.title?.value; - useEffect(() => { - const requestsMeta = [ - { - key: 'industries', - title: 'Industries', - queryToSet: 'eprtrSectorName', - firstInput: { id: _uniqueId('select_'), type: 'select', position: 0 }, - placeholder: 'Select industry', - optionKey: 'eprtrSectorName', - optionValue: 'eprtrSectorName', - optionText: 'eprtrSectorName', - }, - { - key: 'countries', - title: 'Countries', - queryToSet: 'siteCountry', - firstInput: { id: _uniqueId('select_'), type: 'select', position: 0 }, - placeholder: 'Select country code', - optionKey: 'siteCountry', - optionValue: 'siteCountry', - optionText: 'siteCountryName', - }, - ]; - let promises = []; - promises.push( - axios.get( - 'https://discodata.eea.europa.eu/sql?query=SELECT%20DISTINCT%20eprtrSectorName%20FROM%20%5BIED%5D.%5Blatest%5D.%5BEPRTR_sectors%5D%20ORDER%20BY%20eprtrSectorName&p=1&nrOfHits=100', - ), - axios.get( - 'https://discodata.eea.europa.eu/sql?query=SELECT%20DISTINCT%20siteCountry%2C%20siteCountryName%20FROM%20%5BIED%5D.%5Blatest%5D.%5Bvw_Browse2_MapPOPUP%5D%20ORDER%20BY%20siteCountryName', - ), - ); - Promise.all(promises) - .then(response => { - const filtersMeta = { ...state.filtersMeta }; - response.forEach((res, index) => { - const results = JSON.parse(res.request.response).results; - filtersMeta[(requestsMeta[index]?.key)] = { - filteringInputs: [requestsMeta[index]?.firstInput], - placeholder: requestsMeta[index]?.placeholder, - queryToSet: requestsMeta[index]?.queryToSet, - title: requestsMeta[index]?.title, - options: results.map(item => { - return { - key: item[(requestsMeta[index]?.optionKey)], - value: item[(requestsMeta[index]?.optionValue)], - text: item[(requestsMeta[index]?.optionText)], + setState({ ...state, mounted: true }); + return () => { + setState({ ...state, mounted: false }); + }; + /* eslint-disable-next-line */ + }, []); + useEffect(() => { + if (state.mounted) { + let promises = []; + let metadata = []; + const siteCountryFilters = + state.filters.siteCountry && + state.filters.siteCountry.filter(country => country); + const regionFilters = + state.filters.region && state.filters.region.filter(region => region); + const pollutantGroupFilter = + state.filters.pollutantGroup && + state.filters.pollutantGroup.filter(pollutant => pollutant); + const onMountRequests = { + sqls: [ + // INDUSTRIES QUERY + `SELECT DISTINCT eprtrSectorName + FROM [IED].[latest].[EPRTR_sectors] + ORDER BY eprtrSectorName`, + // COUNTRIES QUERY + `SELECT DISTINCT siteCountry, siteCountryName + FROM [IED].[latest].[vw_Browse2_MapPOPUP] + ORDER BY siteCountryName`, + // POLLUTANT GROUPS QUERY + `SELECT DISTINCT pollutantgroup + FROM [IED].[latest].[vw_Browse2_MapPOPUP] + WHERE NOT(pollutantgroup='') + ORDER BY pollutantgroup`, + // REPORTING YEARS QUERY + `SELECT DISTINCT reportingYear FROM [IED].[latest].[ReportData] ORDER BY reportingYear`, + // BAT CONCLUSSIONS QUERY + `SELECT DISTINCT code, Label, AcceptedDate FROM [IED].[latest].[BATConclusionValue] ORDER BY Label`, + ], + meta: [ + // INDUSTRIES META + { + key: 'industries', + title: 'Industries', + queryToSet: 'eprtrSectorName', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select industry', + optionKey: 'eprtrSectorName', + optionValue: 'eprtrSectorName', + optionText: 'eprtrSectorName', + static: true, + }, + // COUNTRIES META + { + key: 'countries', + title: 'Geographical specifics', + queryToSet: 'siteCountry', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select country code', + optionKey: 'siteCountry', + optionValue: 'siteCountry', + optionText: 'siteCountryName', + static: true, + }, + // POLLUTANT GROUPS META + { + key: 'pollutant_groups', + title: 'Pollutants', + queryToSet: 'pollutantGroup', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select pollutant group', + optionKey: 'pollutantgroup', + optionValue: 'pollutantgroup', + optionText: 'pollutantgroup', + static: true, + }, + // REPORTING YEAR META + { + key: 'reporting_years', + title: 'Reporting year', + queryToSet: 'reportingYear', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select reporting year', + optionKey: 'reportingYear', + optionValue: 'reportingYear', + optionText: 'reportingYear', + static: true, + }, + // BAT CONCLUSSIONS QUERY + { + key: 'bat_conclusions', + title: 'BAT Conclusions', + queryToSet: 'batConclusionCode', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select BAT conclusion', + optionKey: 'code', + optionValue: 'code', + optionText: 'Label', + static: true, + }, + ], + }; + const dynamicRequests = { + sqls: [ + // REGION QUERY + siteCountryFilters && + siteCountryFilters.length > 0 && + `SELECT DISTINCT NUTS_ID, NUTS_NAME + FROM [IED].[latest].[refNuts_NoGeo] + WHERE CNTR_CODE IN (${siteCountryFilters.map(country => { + return "'" + country + "'"; + })}) AND LEVL_CODE = 1 + ORDER BY NUTS_NAME`, + // TOWN/VILLAGE QUERY + siteCountryFilters && + regionFilters && + siteCountryFilters.length > 0 && + regionFilters.length && + `SELECT DISTINCT NUTS_ID, NUTS_NAME + FROM [IED].[latest].[refNuts_NoGeo] + WHERE CNTR_CODE IN (${siteCountryFilters.map(country => { + return "'" + country + "'"; + })}) AND (${regionFilters + .map((region, index) => { + return ( + (!index ? '' : 'OR ') + "NUTS_ID LIKE '" + region + "1%'" + ); + }) + .join(' ')}) AND LEVL_CODE = 3 + ORDER BY NUTS_NAME`, + // POLLUTANTS QUERY + pollutantGroupFilter && + pollutantGroupFilter.length > 0 && + `SELECT DISTINCT pollutant + FROM [IED].[latest].[PollutantDict] + WHERE AirPollutantGroup ${pollutantGroupFilter + .map((group, index) => { + return (!index ? "LIKE '%" : "OR '%") + group + "%'"; + }) + .join(' ')} OR WaterPollutantGroup ${pollutantGroupFilter + .map((group, index) => { + return (!index ? "LIKE '%" : "OR '%") + group + "%'"; + }) + .join(' ')} + ORDER BY pollutant`, + ], + meta: [ + // REGION META + siteCountryFilters && + siteCountryFilters.length > 0 && { + key: 'regions', + title: null, + queryToSet: 'region', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select region', + optionKey: 'NUTS_ID', + optionValue: 'NUTS_ID', + optionText: 'NUTS_NAME', + }, + // TOWN/VILLAGE META + siteCountryFilters && + regionFilters && + siteCountryFilters.length > 0 && + regionFilters.length && { + key: 'town_village', + title: null, + queryToSet: 'town_village', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select town/village', + optionKey: 'NUTS_ID', + optionValue: 'NUTS_ID', + optionText: 'NUTS_NAME', + }, + // POLLUTANTS META + pollutantGroupFilter && + pollutantGroupFilter.length > 0 && { + key: 'pollutants', + title: null, + queryToSet: 'pollutant', + firstInput: { + id: _uniqueId('select_'), + type: 'select', + position: 0, + }, + placeholder: 'Select pollutant', + optionKey: 'pollutant', + optionValue: 'pollutant', + optionText: 'pollutant', + }, + ], + }; + onMountRequests.sqls.forEach((sql, index) => { + if (sql && onMountRequests.meta[index]) { + if (!state.firstLoad) { + promises.push(axios.get(makeUrl(providerUrl, sql))); + metadata.push(onMountRequests.meta[index]); + } + } + }); + dynamicRequests.sqls.forEach((sql, index) => { + if (sql && dynamicRequests.meta[index]) { + promises.push(axios.get(makeUrl(providerUrl, sql))); + metadata.push(dynamicRequests.meta[index]); + } + }); + Promise.all(promises) + .then(response => { + if (state.mounted) { + const filtersMeta = { + ...state.filtersMeta, + }; + Object.entries(filtersMeta).forEach(([key, meta]) => { + if (!meta.static) { + delete filtersMeta[key]; + } + }); + response.forEach((res, index) => { + nrOfRequests++; + const results = JSON.parse(res.request.response).results; + let filteringInputs = []; + if (state.filtersMeta[(metadata[index]?.key)]?.filteringInputs) { + filteringInputs = [ + ...state.filtersMeta[metadata[index].key].filteringInputs, + ]; + } + filtersMeta[(metadata[index]?.key)] = { + filteringInputs: filteringInputs.length + ? filteringInputs + : [metadata[index]?.firstInput], + placeholder: metadata[index]?.placeholder, + queryToSet: metadata[index]?.queryToSet, + title: metadata[index]?.title, + static: metadata[index]?.static, + options: [ + { key: null, value: null, text: 'No value' }, + ...(results.map(item => { + return { + key: item[(metadata[index]?.optionKey)], + value: item[(metadata[index]?.optionValue)], + text: item[(metadata[index]?.optionText)], + }; + }) || []), + ], }; - }), - }; - }); - setState({ - ...state, - filtersMeta, - }); - }) - .catch(error => {}); + }); + setState({ + ...state, + filtersMeta, + ...(state.firstLoad === false ? { firstLoad: true } : {}), + }); + } + }) + .catch(error => {}); + } + /* eslint-disable-next-line */ + }, [ + state.mounted, + JSON.stringify(state.filters.eprtrSectorName), + JSON.stringify(state.filters.siteCountry), + JSON.stringify(state.filters.region), + JSON.stringify(state.filters.town_village), + JSON.stringify(state.filters.pollutantGroup), + ]); + // console.log('HERE', nrOfRequests); + useEffect(() => { + updateFilters(); /* eslint-disable-next-line */ - }, []) + }, [JSON.stringify(state.filters), JSON.stringify(state.filtersMeta)]) - const updateFilters = (data, filter, position = 0) => { + const changeFilter = (data, filter, position = 0) => { const newFilters = { ...state.filters }; if (!newFilters[filter.queryToSet]) newFilters[filter.queryToSet] = []; - if (newFilters[filter.queryToSet]?.length - 1 < position) { + if (newFilters[filter.queryToSet]?.length >= position) { + newFilters[filter.queryToSet][position] = data.value; + } else if (newFilters[filter.queryToSet]?.length < position) { for (let i = 0; i < newFilters[filter.queryToSet].length; i++) { if (typeof newFilters[filter.queryToSet][i] === 'undefined') newFilters[filter.queryToSet][i] = null; } - newFilters[filter.queryToSet][position] = data.value; - } else if (newFilters[filter.queryToSet]?.length - 1 >= position) { - newFilters[filter.queryToSet][position] = data.value; } setState({ ...state, @@ -94,6 +364,38 @@ const View = ({ content, ...props }) => { }); }; + const updateFilters = () => { + const newFilters = { ...state.filters }; + const newFiltersKeys = Object.keys(newFilters); + const filtersMetaEntries = Object.entries(state.filtersMeta); + const filtersMetaKeys = filtersMetaEntries.map(([key, value]) => { + return value.queryToSet; + }); + + newFiltersKeys + .filter(key => !filtersMetaKeys.includes(key)) + .forEach(key => { + newFilters[key] = []; + }); + filtersMetaEntries.forEach(([key, value]) => { + if (newFilters[value.queryToSet]) { + const options = value.options.map(item => item.value); + newFilters[value.queryToSet] = newFilters[value.queryToSet].map( + item => { + if (options.includes(item)) return item; + return null; + }, + ); + } + }); + if (JSON.stringify(newFilters) !== JSON.stringify(state.filters)) { + setState({ + ...state, + filters: newFilters, + }); + } + }; + const addNewInput = (key, type, position = 0) => { const newFiltersMeta = { ...state.filtersMeta }; newFiltersMeta[key].filteringInputs.push({ @@ -102,11 +404,51 @@ const View = ({ content, ...props }) => { position, }); setState({ - ...state.filtersMeta, + ...state, filtersMeta: newFiltersMeta, }); }; + const removeInput = (key, filter, position = 0) => { + const newFiltersMeta = { ...state.filtersMeta }; + if ( + newFiltersMeta[key].filteringInputs && + newFiltersMeta[key].filteringInputs.length > 1 + ) { + newFiltersMeta[key].filteringInputs.pop(); + if ( + state.filters[filter.queryToSet]?.length > 0 && + state.filters[filter.queryToSet][position] + ) { + const newfilters = { ...state.filters }; + newfilters[filter.queryToSet].pop(); + setState({ ...state, filters: newfilters }); + } + } + setState({ + ...state, + filtersMeta: newFiltersMeta, + }); + }; + + const clearFilters = () => { + const newFilters = { ...state.filters }; + Object.keys(newFilters).forEach(filter => { + newFilters[filter] = newFilters[filter].map(value => null); + }); + setState({ + ...state, + filters: newFilters, + }); + }; + + const submit = () => { + props.setQueryParam({ + queryParam: { ...state.filters }, + }); + setState({ ...state, open: false }); + }; + return ( { > {/* eslint-disable-next-line */} - Advanced search and filter setState({ ...state, open: false })}>X + Advanced search and filter + setState({ ...state, open: false })} + color="red" + name={clear} + size="1em" + />
Search terms
- +
+ + + + + +
+
- +
{state.filtersMeta && - Object.entries(state.filtersMeta).map(([filterKey, filterValue]) => { + state.filtersMetaOrder && + state.filtersMetaOrder.map(filterKey => { return ( - -
{filterValue.title}
- {filterValue?.filteringInputs?.length && - filterValue.filteringInputs.map((input, index) => { - if (input.type === 'select') { - return ( - <> - + changeFilter( + data, + state.filtersMeta[filterKey], + input.position, + ) } - > -