diff --git a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx index 24a6e7d1..34ae95c2 100644 --- a/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx +++ b/src/components/manage/Blocks/DiscodataOpenlayersMapBlock/View.jsx @@ -12,6 +12,7 @@ import axios from 'axios'; import jsonp from 'jsonp'; import config from '@plone/volto/registry'; import { isArray } from 'lodash'; +import { getEncodedQueryString } from '~/utils'; // VOLTO import { Icon as VoltoIcon, Toast } from '@plone/volto/components'; import PrivacyProtection from './PrivacyProtection'; @@ -67,9 +68,7 @@ let Map, tile, Control, defaultsControls, - defaultsInteractions, - containsExtent, - VOID; + defaultsInteractions; let OL_LOADED = false; const OpenlayersMapView = (props) => { @@ -173,8 +172,6 @@ const OpenlayersMapView = (props) => { Control = require('ol/control/Control.js').default; defaultsControls = require('ol/control.js').defaults; defaultsInteractions = require('ol/interaction.js').defaults; - containsExtent = require('ol/extent.js').containsExtent; - VOID = require('ol/functions').VOID; OL_LOADED = true; } @@ -235,8 +232,8 @@ const OpenlayersMapView = (props) => { radius: 3, fill: new Fill({ color: '#00FF00' }), stroke: new Stroke({ color: '#6A6A6A', width: 1 }), - zIndex: 1, }), + zIndex: 1, }), ); } @@ -266,6 +263,7 @@ const OpenlayersMapView = (props) => { onSourceChange(); } else if (['byAdvancedFilters'].includes(state.updateMapPosition)) { onSourceChange(); + // TODO: verifica nebunii if (!state.map.sitesSourceLayer.getVisible()) { state.map.sitesSourceLayer.setVisible(true); } @@ -293,6 +291,7 @@ const OpenlayersMapView = (props) => { renderMap(); setMapRendered(true); } + /* eslint-disable-next-line */ }, [prepareMapRender]); if (mapRendered && mounted.current && !firstFilteringUpdate) { @@ -397,11 +396,11 @@ const OpenlayersMapView = (props) => { Object.entries(sitesSourceQuery.whereStatements).forEach(([id, where]) => { let options; if (['string', 'multiple'].includes(where.type)) { - options = props.discodata_query.search[id]; - } else if (!props.discodata_query.search[id]) { + options = props.query[id]; + } else if (!props.query[id]) { options = null; } else { - options = splitBy(props.discodata_query.search[id], ','); + options = splitBy(props.query[id], ','); } if (where.type === 'multiple') { @@ -428,8 +427,8 @@ const OpenlayersMapView = (props) => { if (filterSource !== 'query_params') { if ( - props.discodata_query.search.advancedFiltering && - props.discodata_query.search.nuts_latest?.length > 0 + props.query.advancedFiltering && + props.query.nuts_latest?.length > 0 ) { updateMapPosition = 'byAdvancedFilters'; } else { @@ -576,14 +575,12 @@ const OpenlayersMapView = (props) => { if (stateRef.current.siteTerm) { axios .get( - encodeURI( - `${ - config.settings.providerUrl - }?query=SELECT shape_wm.STX as x, shape_wm.STY as y, Site_reporting_year from [IED].[latest].[SiteMap] WHERE siteName COLLATE Latin1_General_CI_AI LIKE '%${stateRef.current.siteTerm.replace( + `${config.settings.providerUrl}?${getEncodedQueryString( + `SELECT shape_wm.STX as x, shape_wm.STY as y, Site_reporting_year, siteName from [IED].[latest].[SiteMap] WHERE siteName COLLATE Latin1_General_CI_AI LIKE '%${stateRef.current.siteTerm.replace( "'", "''", )}%' ORDER BY [Site_reporting_year] DESC`, - ), + )}`, ) .then((response) => { const data = JSON.parse(response.request.response); @@ -649,19 +646,17 @@ const OpenlayersMapView = (props) => { } else { axios .get( - encodeURI( - `${config.settings.providerUrl}?query=SELECT + `${config.settings.providerUrl}?${getEncodedQueryString(`SELECT MIN(shape_wm.STX) AS MIN_X, MIN(shape_wm.STY) AS MIN_Y, MAX(shape_wm.STX) AS MAX_X, MAX(shape_wm.STY) AS MAX_Y - FROM [IED].[latest].[SiteMap] - ${ - stateRef.current.map.sitesSourceQuery.where - ? 'WHERE ' + stateRef.current.map.sitesSourceQuery.where - : '' - }`, - ), + FROM [IED].[latest].[SiteMap] + ${ + stateRef.current.map.sitesSourceQuery.where + ? 'WHERE ' + stateRef.current.map.sitesSourceQuery.where + : '' + }`)}`, ) .then((response) => { const data = JSON.parse(response.request.response); @@ -880,6 +875,7 @@ const OpenlayersMapView = (props) => { let reqs = 0; sitesSource = new VectorSource({ loader: function (extent, resolution, projection) { + this.resolution = resolution; if (mounted.current && firstFilteringDone.current) { let url = `https://air.discomap.eea.europa.eu/arcgis/rest/services/Air/IED_SiteMap/FeatureServer/0/query/?f=json&returnGeometry=true&spatialRel=esriSpatialRelIntersects&geometry=${encodeURIComponent( '{"xmin":' + @@ -905,9 +901,7 @@ const OpenlayersMapView = (props) => { }, (error, response) => { reqs--; - if (error) { - console.log(error.message); - } else { + if (!error) { let features = esrijsonFormat.readFeatures(response, { featureProjection: projection, }); @@ -924,14 +918,11 @@ const OpenlayersMapView = (props) => { }, strategy: function (extent, resolution) { const tileGrid = createXYZ({ - tileSize: 512, - maxZoom: zoomSwitch, + tileSize: 256, }); - if (this.resolution && this.resolution !== resolution) { this.loadedExtentsRtree_.clear(); } - let z = tileGrid.getZForResolution(resolution); let tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z); /** @type {Array} */ @@ -955,38 +946,6 @@ const OpenlayersMapView = (props) => { }, }); - sitesSource.loadFeatures = function (extent, resolution, projection) { - let loadedExtentsRtree = this.loadedExtentsRtree_; - let extentsToLoad = this.strategy_(extent, resolution); - this.loading = false; - let _loop_1 = function (i, ii) { - let extentToLoad = extentsToLoad[i]; - let alreadyLoaded = loadedExtentsRtree.forEachInExtent( - extentToLoad, - /** - * @param {{extent: import("../extent.js").Extent}} object Object. - * @return {boolean} Contains. - */ - function (object) { - return containsExtent(object.extent, extentToLoad); - }, - ); - - if (!alreadyLoaded) { - this_1.loader_.call(this_1, extentToLoad, resolution, projection); - loadedExtentsRtree.insert(extentToLoad, { - extent: extentToLoad.slice(), - }); - this_1.loading = this_1.loader_ !== VOID; - } - }; - let this_1 = this; - for (let i = 0, ii = extentsToLoad.length; i < ii; ++i) { - _loop_1(i, ii); - } - this.resolution = resolution; - }; - // Make regions source layer if (hasRegionsFeatures) { regionsSource = new VectorSource({ @@ -1013,9 +972,7 @@ const OpenlayersMapView = (props) => { : '') + '&callback', }, (error, response) => { - if (error) { - console.log(error.message); - } else { + if (!error) { let features = esrijsonFormat.readFeatures(response, { featureProjection: projection, }); @@ -1028,7 +985,7 @@ const OpenlayersMapView = (props) => { }, strategy: tile( createXYZ({ - tileSize: 512, + tileSize: 256, }), ), }); @@ -1048,7 +1005,7 @@ const OpenlayersMapView = (props) => { visible: true, title: 'ied_SiteMap', }); - // Regions source layerq + // Regions source layer if (hasRegionsFeatures) { regionsSourceLayer = new VectorLayer({ source: regionsSource, @@ -1096,9 +1053,8 @@ const OpenlayersMapView = (props) => { (position) => { return centerPosition(map, position, 12); }, - (error) => { - console.log(error); - }, + // Errors + () => {}, ); } else { map.getView().fit([extent[0], extent[1], extent[2], extent[3]]); @@ -1113,10 +1069,14 @@ const OpenlayersMapView = (props) => { ); setSelectedSite(closestFeature); selectedSiteCoordinates.current = null; + } else if (selectedSite) { + setSelectedSite(null); } } }); + // TODO: REVIEW + // ============== if (hasPopups) { if (document && document.documentElement?.clientWidth > 500) { map.on('pointermove', function (evt) { @@ -1190,35 +1150,10 @@ const OpenlayersMapView = (props) => { element: popupDetails, }, }); + // ============== } } - const setSiteQueryParams = () => { - return new Promise((resolve, reject) => { - axios - .get( - encodeURI( - `${config.settings.providerUrl}?query=SELECT DISTINCT siteId, siteInspireId FROM [IED].[latest].[FacilitiesPerSite] WHERE siteId LIKE '${state.popupDetails.properties.id}'`, - ), - ) - .then((response) => { - const data = JSON.parse(response.request.response); - props.setQueryParam({ - queryParam: { - siteInspireId: data.results[0].siteInspireId, - siteId: state.popupDetails.properties.id, - siteName: state.popupDetails.properties.siteName, - siteReportingYear: - state.popupDetails.properties.Site_reporting_year, - }, - }); - resolve(true); - }) - .catch((error) => { - reject(false); - }); - }); - }; if (!__CLIENT__) return ''; const view = ( @@ -1371,8 +1306,9 @@ const OpenlayersMapView = (props) => { Site Details @@ -1392,9 +1328,8 @@ const OpenlayersMapView = (props) => { (position) => { return centerPosition(state.map.element, position, 12); }, - (error) => { - console.log(error); - }, + // Error + () => {}, { timeout: 10000 }, ); } @@ -1436,7 +1371,10 @@ const OpenlayersMapView = (props) => { export default compose( connect( (state, props) => ({ - query: qs.parse(state.router.location.search.replace('?', '')), + query: { + ...(state.discodata_query.search || {}), + ...(qs.parse(state.router.location.search.replace('?', '')) || {}), + }, content: state.prefetch?.[state.router.location.pathname] || state.content.data, discodata_query: state.discodata_query, diff --git a/src/components/manage/Blocks/FiltersBlock/View.jsx b/src/components/manage/Blocks/FiltersBlock/View.jsx index bf70c643..7393f485 100644 --- a/src/components/manage/Blocks/FiltersBlock/View.jsx +++ b/src/components/manage/Blocks/FiltersBlock/View.jsx @@ -4,13 +4,14 @@ import { compose } from 'redux'; import { connect } from 'react-redux'; import { Header, Modal, Select, Input, List } from 'semantic-ui-react'; import { Portal } from 'react-portal'; +import _uniqueId from 'lodash/uniqueId'; +import axios from 'axios'; +import Highlighter from 'react-highlight-words'; import { Icon } from '@plone/volto/components'; import { DiscodataSqlBuilderView } from 'volto-datablocks/components'; import { setQueryParam, deleteQueryParam } from 'volto-datablocks/actions'; import config from '@plone/volto/registry'; -import _uniqueId from 'lodash/uniqueId'; -import axios from 'axios'; -import Highlighter from 'react-highlight-words'; +import { getEncodedQueryString } from '~/utils'; import menuSVG from '@plone/volto/icons/menu-alt.svg'; import circlePlus from '@plone/volto/icons/circle-plus.svg'; @@ -523,7 +524,10 @@ const View = ({ content, ...props }) => { }) || []), ], }; - if (metadata[index]?.key === 'reporting_years') { + if ( + metadata[index]?.key === 'reporting_years' && + !props.discodata_query.search.reportingYear?.length + ) { const reportingYears = res.data?.results ?.map((item) => item.reportingYear) @@ -534,7 +538,10 @@ const View = ({ content, ...props }) => { ]; } } - if (metadata[index]?.key === 'countries') { + if ( + metadata[index]?.key === 'countries' && + !props.discodata_query.search.siteCountryNames?.length + ) { newQueryParams.siteCountryNames = res.data?.results || []; } }); @@ -831,7 +838,7 @@ const View = ({ content, ...props }) => { sqls.forEach((sql) => { promises.push({ get: axios.get( - providerUrl + `?query=${encodeURI(sql.query)}&p=1&nrOfHits=6`, + providerUrl + `?${getEncodedQueryString(sql.query)}&p=1&nrOfHits=6`, ), metadata: sql, }); diff --git a/src/components/manage/Blocks/SiteBlocks/Header/View.jsx b/src/components/manage/Blocks/SiteBlocks/Header/View.jsx index 56e67e88..3ac11f60 100644 --- a/src/components/manage/Blocks/SiteBlocks/Header/View.jsx +++ b/src/components/manage/Blocks/SiteBlocks/Header/View.jsx @@ -2,6 +2,7 @@ import React from 'react'; import { compose } from 'redux'; import { connect } from 'react-redux'; import { Grid, Dropdown } from 'semantic-ui-react'; +import { setQueryParam } from 'volto-datablocks/actions'; import qs from 'querystring'; import './style.css'; @@ -10,12 +11,23 @@ const getQueryString = (query) => { return '?' + qs.stringify(query); }; +const getSiteByYear = (provider_data, year) => { + const index = provider_data?.euregReportingYear?.indexOf(year); + const keys = Object.keys(provider_data || {}); + const site = {}; + if (keys?.length) { + keys.forEach((key) => { + site[key] = provider_data[key][index]; + }); + } + return site; +}; + const View = (props) => { const [siteHeader, setSiteHeader] = React.useState({}); const { provider_data = {} } = props; const query = { ...props.query }; const siteReportingYear = parseInt(query.siteReportingYear || ''); - const index = provider_data?.euregReportingYear?.indexOf(siteReportingYear); const reportingYears = provider_data?.euregReportingYear?.length ? provider_data.euregReportingYear @@ -29,15 +41,32 @@ const View = (props) => { : []; React.useEffect(() => { - const keys = Object.keys(provider_data || {}); - if (keys?.length) { - const newSiteHeader = {}; - keys.forEach((key) => { - newSiteHeader[key] = provider_data[key][index]; + if ( + siteHeader?.siteName && + siteReportingYear && + (siteHeader.siteName !== props.discodata_query.siteTerm || + siteReportingYear !== props.discodata_query.reportingYear?.[0]) + ) { + props.setQueryParam({ + queryParam: { + siteTerm: siteHeader.siteName, + reportingYear: [siteReportingYear], + ...(props.discodata_query.siteTerm + ? { + filtersCounter: + (props.discodata_query['filtersCounter'] || 0) + 1, + } + : {}), + }, }); - setSiteHeader(newSiteHeader); } - }, [provider_data, index]); + /* eslint-disable-next-line */ + }, [JSON.stringify(siteHeader)]); + + React.useEffect(() => { + setSiteHeader(getSiteByYear(provider_data, siteReportingYear)); + /* eslint-disable-next-line */ + }, [JSON.stringify(provider_data), siteReportingYear]); return props.mode === 'edit' ? (

Site header

@@ -121,11 +150,13 @@ const View = (props) => { { + const newSite = getSiteByYear(provider_data, data.value); props.history.push({ pathname: props.location.pathname, search: getQueryString({ ...props.query, siteReportingYear: data.value, + siteName: newSite.siteName, }), state: { ignoreScrollBehavior: true, @@ -148,7 +179,11 @@ const View = (props) => { }; export default compose( - connect((state, props) => ({ - query: qs.parse(state.router.location.search.replace('?', '')), - })), + connect( + (state, props) => ({ + query: qs.parse(state.router.location.search.replace('?', '')), + discodata_query: state.discodata_query.search, + }), + { setQueryParam }, + ), )(View); diff --git a/src/config.js b/src/config.js index 8e1be67b..f2a12785 100644 --- a/src/config.js +++ b/src/config.js @@ -116,6 +116,12 @@ import worldSVG from '@plone/volto/icons/world.svg'; // All your imports required for the config here BEFORE this line import '@plone/volto/config'; +import { getEncodedString } from '~/utils'; + +// eslint-disable-next-line no-extend-native +String.prototype.encoded = function encoded() { + return this ? getEncodedString(this) : ''; +}; export default function applyConfig(config) { // Add here your project's configuration here by modifying `config` accordingly diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 00000000..1cf357e1 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,29 @@ +import qs from 'querystring'; + +export const getEncodedQueryString = (str) => { + if (str) { + return qs.stringify( + { query: str }, + { + arrayFormat: 'comma', + encode: true, + }, + ); + } + return ''; +}; + +export const getEncodedString = (str) => { + if (str) { + return qs + .stringify( + { str }, + { + arrayFormat: 'comma', + encode: true, + }, + ) + .replace('str=', ''); + } + return ''; +};