@eeacms/volto-cca-policy 0.3.46 → 0.3.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/jest-addon.config.js +421 -6
  3. package/package.json +2 -2
  4. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyMap.jsx +7 -5
  5. package/src/components/manage/Blocks/CaseStudyExplorer/CaseStudyMap.test.jsx +17 -0
  6. package/src/components/manage/Blocks/CaseStudyExplorer/FeatureInteraction.jsx +8 -7
  7. package/src/components/manage/Blocks/CaseStudyExplorer/useInteractiveStyles.jsx +37 -31
  8. package/src/components/manage/Blocks/CaseStudyExplorer/utils.js +1 -3
  9. package/src/components/manage/Blocks/CountryMapObservatory/CountryMapObservatoryOLView.jsx +5 -4
  10. package/src/components/manage/Blocks/CountryMapObservatory/mapstyle.js +3 -5
  11. package/src/components/manage/Blocks/index.js +7 -6
  12. package/src/components/theme/MissionSignatoryProfile/MissionSignatoryProfileView.jsx +14 -3
  13. package/src/components/theme/MissionSignatoryProfile/MissionSignatoryProfileView.test.jsx +16 -5
  14. package/src/index.js +2 -2
  15. package/theme/globals/mission.less +13 -0
  16. package/src/components/manage/Blocks/MKHMap/Edit.jsx +0 -29
  17. package/src/components/manage/Blocks/MKHMap/FeatureDisplay.jsx +0 -87
  18. package/src/components/manage/Blocks/MKHMap/FeatureInteraction.jsx +0 -56
  19. package/src/components/manage/Blocks/MKHMap/InfoOverlay.jsx +0 -80
  20. package/src/components/manage/Blocks/MKHMap/View.jsx +0 -118
  21. package/src/components/manage/Blocks/MKHMap/index.js +0 -25
  22. package/src/components/manage/Blocks/MKHMap/layers.js +0 -107
  23. package/src/components/manage/Blocks/MKHMap/map.svg +0 -3
  24. package/src/components/manage/Blocks/MKHMap/schema.js +0 -15
  25. package/src/components/manage/Blocks/MKHMap/styles.less +0 -41
  26. package/src/components/manage/Blocks/MKHMap/useWhyDidYouUpdate.js +0 -33
  27. package/src/components/theme/MissionSignatoryProfile/TabSections/IntroductionTab.jsx +0 -37
@@ -1,8 +1,7 @@
1
1
  import React from 'react';
2
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
3
2
  const _cached = {};
4
3
 
5
- function getStyle(size, haveAdaptecca) {
4
+ function getStyle(size, haveAdaptecca, ol) {
6
5
  let style = _cached[size + '_' + haveAdaptecca];
7
6
 
8
7
  if (!style) {
@@ -41,26 +40,29 @@ function getStyle(size, haveAdaptecca) {
41
40
  return style;
42
41
  }
43
42
 
44
- export function useStyles() {
45
- const selectStyle = React.useCallback((feature) => {
46
- const selected = new ol.style.Style({
47
- image: new ol.style.Circle({
48
- radius: 12,
49
- fill: new ol.style.Fill({
50
- color: '#005c96',
51
- }),
52
- stroke: new ol.style.Stroke({
53
- color: 'rgba(0, 92, 150, 0.9)',
54
- width: 2,
43
+ export function useStyles(ol) {
44
+ const selectStyle = React.useCallback(
45
+ (feature) => {
46
+ const selected = new ol.style.Style({
47
+ image: new ol.style.Circle({
48
+ radius: 12,
49
+ fill: new ol.style.Fill({
50
+ color: '#005c96',
51
+ }),
52
+ stroke: new ol.style.Stroke({
53
+ color: 'rgba(0, 92, 150, 0.9)',
54
+ width: 2,
55
+ }),
55
56
  }),
56
- }),
57
- });
58
- // const color = feature.get('COLOR') || '#eeeeee';
59
- // selected.getFill().setColor(color);
60
- const color = feature.values_.features[0].values_['color'] || '#ccc';
61
- selected.image_.getFill().setColor(color);
62
- return selected;
63
- }, []);
57
+ });
58
+ // const color = feature.get('COLOR') || '#eeeeee';
59
+ // selected.getFill().setColor(color);
60
+ const color = feature.values_.features[0].values_['color'] || '#ccc';
61
+ selected.image_.getFill().setColor(color);
62
+ return selected;
63
+ },
64
+ [ol],
65
+ );
64
66
 
65
67
  const convexHullStroke = React.useMemo(
66
68
  () =>
@@ -68,7 +70,7 @@ export function useStyles() {
68
70
  color: 'rgba(204, 85, 0, 1)',
69
71
  width: 1.5,
70
72
  }),
71
- [],
73
+ [ol],
72
74
  );
73
75
 
74
76
  const clusterMemberStyle = React.useMemo(() => {
@@ -85,7 +87,7 @@ export function useStyles() {
85
87
  });
86
88
  };
87
89
  return _clusterMemberStyle;
88
- }, []);
90
+ }, [ol]);
89
91
 
90
92
  const clusterCircleStyle = React.useCallback(
91
93
  (cluster, resolution) => {
@@ -135,7 +137,7 @@ export function useStyles() {
135
137
  return styles;
136
138
  }, []);
137
139
  },
138
- [convexHullStroke, clusterMemberStyle],
140
+ [convexHullStroke, clusterMemberStyle, ol],
139
141
  );
140
142
 
141
143
  return { clusterCircleStyle, selectStyle };
@@ -169,16 +171,20 @@ export function generatePointsCircle(count, clusterCenter, resolution) {
169
171
 
170
172
  return res;
171
173
  }
172
- export function clusterStyle(feature) {
173
- const size = feature.get('features').length;
174
- const cases = feature
175
- .get('features')
176
- .filter((_case) => _case['values_']['origin_adaptecca'] < 20);
177
174
 
178
- return getStyle(size, cases.length > 0 ? 1 : 0);
175
+ export function clusterStyle(ol) {
176
+ function _closure(feature) {
177
+ const size = feature.get('features').length;
178
+ const cases = feature
179
+ .get('features')
180
+ .filter((_case) => _case['values_']['origin_adaptecca'] < 20);
181
+
182
+ return getStyle(size, cases.length > 0 ? 1 : 0, ol);
183
+ }
184
+ return _closure;
179
185
  }
180
186
 
181
- export function getExtentOfFeatures(features) {
187
+ export function getExtentOfFeatures(features, ol) {
182
188
  const points = features.map((f) => f.getGeometry().flatCoordinates);
183
189
  const point = new ol.geom.MultiPoint(points);
184
190
  return point.getExtent();
@@ -1,6 +1,4 @@
1
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
2
-
3
- export function getFeatures(cases) {
1
+ export function getFeatures(cases, ol) {
4
2
  const Feature = ol.ol.Feature;
5
3
 
6
4
  return cases.map((c, index) => {
@@ -4,8 +4,8 @@ import { compose } from 'redux';
4
4
  import { clientOnly } from '@eeacms/volto-cca-policy/helpers';
5
5
  import { useHistory } from 'react-router-dom';
6
6
 
7
+ import { withOpenLayers } from '@eeacms/volto-openlayers-map';
7
8
  import { Map, Layer, Layers, Controls } from '@eeacms/volto-openlayers-map/api';
8
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
9
9
  import {
10
10
  euCountryNames,
11
11
  tooltipStyle,
@@ -24,10 +24,10 @@ import './styles.less';
24
24
  // 'https://raw.githubusercontent.com/eurostat/Nuts2json/master/pub/v2/2021/4326/20M/cntrg.json';
25
25
 
26
26
  const CountryMapObservatoryView = (props) => {
27
- const { geofeatures, projection } = props;
27
+ const { geofeatures, projection, ol } = props;
28
28
 
29
29
  const history = useHistory();
30
- const styles = React.useMemo(makeStyles, []);
30
+ const styles = React.useMemo(() => makeStyles(ol), [ol]);
31
31
  const tooltipRef = React.useRef();
32
32
  const [tileWMSSources, setTileWMSSources] = React.useState();
33
33
  const [overlaySource, setOverlaySource] = React.useState();
@@ -75,7 +75,7 @@ const CountryMapObservatoryView = (props) => {
75
75
  transition: 0,
76
76
  }),
77
77
  ]);
78
- }, [geofeatures]);
78
+ }, [geofeatures, ol]);
79
79
 
80
80
  const baseUrl = getBaseUrl(props);
81
81
 
@@ -131,4 +131,5 @@ export default compose(
131
131
  withGeoJsonData,
132
132
  withResponsiveContainer('countryMapObservatory'),
133
133
  withVisibilitySensor(),
134
+ withOpenLayers,
134
135
  )(CountryMapObservatoryView);
@@ -1,6 +1,4 @@
1
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
2
-
3
- const flagRenderer = ({ stroke, fill }) => (pixelCoordinates, state) => {
1
+ const flagRenderer = ({ stroke, fill, ol }) => (pixelCoordinates, state) => {
4
2
  const context = state.context;
5
3
  const geometry = state.geometry.clone();
6
4
  geometry.setCoordinates(pixelCoordinates);
@@ -29,7 +27,7 @@ const flagRenderer = ({ stroke, fill }) => (pixelCoordinates, state) => {
29
27
  context.restore();
30
28
  };
31
29
 
32
- export const makeStyles = () => {
30
+ export const makeStyles = (ol) => {
33
31
  const fill = new ol.style.Fill();
34
32
  const stroke = new ol.style.Stroke({
35
33
  // color: 'rgba(255,255,255,0.8)',
@@ -45,7 +43,7 @@ export const makeStyles = () => {
45
43
  fill: new ol.style.Fill({
46
44
  color: 'rgb(1, 112, 183, 0.8)',
47
45
  }),
48
- renderer: flagRenderer({ fill, stroke }),
46
+ renderer: flagRenderer({ fill, stroke, ol }),
49
47
  });
50
48
 
51
49
  const eucountriesStyle = new ol.style.Style({
@@ -1,6 +1,5 @@
1
1
  import { compose } from 'redux';
2
2
 
3
- // import installMKHMap from './MKHMap';
4
3
  import installECDEIndicatorsBlock from './ECDEIndicators';
5
4
  import installCaseStudyExplorerBlock from './CaseStudyExplorer';
6
5
  import installSearchAceContent from './SearchAceContent';
@@ -8,8 +7,6 @@ import installRelevantAceContent from './RelevantAceContent';
8
7
  import installFilterAceContent from './FilterAceContent';
9
8
  import installTransRegionSelect from './TransRegionSelect';
10
9
  import installCountryMapObservatory from './CountryMapObservatory';
11
- import installCountryMapHeatIndex from './CountryMapHeatIndex';
12
- import installCountryMapProfile from './CountryMapProfile';
13
10
  import installCountryProfileDetail from './CountryProfileDetail';
14
11
  import installListing from './Listing';
15
12
  import installRAST from './RASTBlock';
@@ -23,6 +20,10 @@ import installRedirectBlock from './RedirectBlock';
23
20
  import installContentLinks from './ContentLinks';
24
21
  import installASTNavigation from './ASTNavigation';
25
22
 
23
+ // import installMKHMap from './MKHMap';
24
+ // import installCountryMapHeatIndex from './CountryMapHeatIndex';
25
+ // import installCountryMapProfile from './CountryMapProfile';
26
+
26
27
  export default function installBlocks(config) {
27
28
  config.blocks.blocksConfig.title.restricted = false;
28
29
  config.blocks.blocksConfig.layoutSettings.restricted = false;
@@ -36,12 +37,9 @@ export default function installBlocks(config) {
36
37
  installC3SIndicatorsOverviewBlock,
37
38
  installC3SIndicatorsListingBlock,
38
39
  installC3SIndicatorsGlossaryBlock,
39
- // installMKHMap,
40
40
  installECDEIndicatorsBlock,
41
41
  installCaseStudyExplorerBlock,
42
42
  installCountryMapObservatory,
43
- installCountryMapHeatIndex,
44
- installCountryMapProfile,
45
43
  installCountryProfileDetail,
46
44
  installSearchAceContent,
47
45
  installRelevantAceContent,
@@ -53,5 +51,8 @@ export default function installBlocks(config) {
53
51
  installRedirectBlock,
54
52
  installContentLinks,
55
53
  installASTNavigation,
54
+ // installMKHMap,
55
+ // installCountryMapHeatIndex,
56
+ // installCountryMapProfile,
56
57
  )(config);
57
58
  }
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
- import { Tab, Container, Divider } from 'semantic-ui-react';
2
+ import { Link } from 'react-router-dom';
3
+ import { Tab, Container, Divider, Button, Icon } from 'semantic-ui-react';
3
4
  import { formatTextToHTML } from '@eeacms/volto-cca-policy/utils';
4
5
  import { BannerTitle, HTMLField } from '@eeacms/volto-cca-policy/helpers';
6
+ import { flattenToAppURL } from '@plone/volto/helpers';
5
7
 
6
8
  import GovernanceTab from './TabSections/GovernanceTab';
7
9
  import AssessmentTab from './TabSections/AssessmentTab';
@@ -29,6 +31,9 @@ const MissionSignatoryProfileView = ({ content }) => {
29
31
  general_text = [{}],
30
32
  } = signatoryData;
31
33
 
34
+ const { Back_To_Map_Link, Country_Or_Area } = general_text?.[0] || {};
35
+ const backToMapPath = flattenToAppURL(content?.parent?.['@id'] || '/');
36
+
32
37
  const [activeIndex, setActiveIndex] = React.useState(0);
33
38
 
34
39
  const tabData = {
@@ -60,12 +65,18 @@ const MissionSignatoryProfileView = ({ content }) => {
60
65
  hidePublishingDate: true,
61
66
  hideDownloadButton: false,
62
67
  hideShareButton: false,
63
- subtitle: general_text?.[0]?.Country_Or_Area,
68
+ subtitle: Country_Or_Area,
64
69
  }}
65
70
  />
66
71
 
67
72
  <div className="signatory-profile">
68
- <br />
73
+ <Link to={backToMapPath}>
74
+ <Button icon inverted primary className="left labeled back-to-map">
75
+ <Icon className="chevron left icon" />
76
+ {Back_To_Map_Link || 'Back to Signatories map'}
77
+ </Button>
78
+ </Link>
79
+
69
80
  <Tab
70
81
  menu={{
71
82
  fluid: true,
@@ -1,4 +1,5 @@
1
1
  import { render, fireEvent, screen } from '@testing-library/react';
2
+ import { MemoryRouter } from 'react-router-dom';
2
3
  import '@testing-library/jest-dom';
3
4
  import MissionSignatoryProfileView from './MissionSignatoryProfileView';
4
5
 
@@ -38,15 +39,25 @@ describe('MissionSignatoryProfileView', () => {
38
39
  { key: 'Action_Label', value: 'Action' },
39
40
  { key: 'Language', value: 'en' },
40
41
  ],
42
+ general_text: [
43
+ {
44
+ Back_To_Map_Link: 'Back to map',
45
+ Country_Or_Area: 'Testland',
46
+ },
47
+ ],
41
48
  },
42
49
  },
43
50
  },
51
+ parent: {
52
+ '@id': '/signatories-map',
53
+ },
44
54
  };
45
55
 
56
+ const renderWithRouter = (ui) => render(<MemoryRouter>{ui}</MemoryRouter>);
57
+
46
58
  it('renders tab labels and default content', () => {
47
- render(<MissionSignatoryProfileView content={content} />);
59
+ renderWithRouter(<MissionSignatoryProfileView content={content} />);
48
60
 
49
- // Tab labels
50
61
  expect(screen.getByText('Governance')).toBeInTheDocument();
51
62
  expect(screen.getByText('Assessment')).toBeInTheDocument();
52
63
  expect(screen.getByText('Planning & Target')).toBeInTheDocument();
@@ -54,7 +65,7 @@ describe('MissionSignatoryProfileView', () => {
54
65
  });
55
66
 
56
67
  it('switches tabs and renders corresponding content', () => {
57
- render(<MissionSignatoryProfileView content={content} />);
68
+ renderWithRouter(<MissionSignatoryProfileView content={content} />);
58
69
 
59
70
  fireEvent.click(screen.getByText('Governance'));
60
71
  expect(screen.getByText('Mocked Governance')).toBeInTheDocument();
@@ -70,10 +81,10 @@ describe('MissionSignatoryProfileView', () => {
70
81
  });
71
82
 
72
83
  it('renders footer disclaimer text if present', () => {
73
- render(<MissionSignatoryProfileView content={content} />);
84
+ renderWithRouter(<MissionSignatoryProfileView content={content} />);
74
85
  expect(screen.getByText('Disclaimer Title')).toBeInTheDocument();
75
86
  expect(
76
- screen.getByText((content) => content.includes('This is a disclaimer.')),
87
+ screen.getByText((text) => text.includes('This is a disclaimer.')),
77
88
  ).toBeInTheDocument();
78
89
  });
79
90
  });
package/src/index.js CHANGED
@@ -22,7 +22,7 @@ import C3SIndicatorView from './components/theme/Views/C3SIndicatorView';
22
22
  import DatabaseItemView from './components/theme/Views/DatabaseItemView';
23
23
 
24
24
  import GeocharsWidget from './components/theme/Widgets/GeocharsWidget';
25
- import GeolocationWidget from './components/theme/Widgets/GeolocationWidget';
25
+ // import GeolocationWidget from './components/theme/Widgets/GeolocationWidget';
26
26
  import PromotionalImageWidget from './components/theme/Widgets/PromotionalImageWidget';
27
27
  import MigrationButtons from './components/MigrationButtons';
28
28
  import HealthHorizontalCardItem from './components/Result/HealthHorizontalCardItem';
@@ -429,7 +429,7 @@ const applyConfig = (config) => {
429
429
  };
430
430
  // Custom widgets
431
431
  config.widgets.id.geochars = GeocharsWidget;
432
- config.widgets.id.geolocation = GeolocationWidget;
432
+ // config.widgets.id.geolocation = GeolocationWidget;
433
433
  config.widgets.id.promotional_image = PromotionalImageWidget;
434
434
 
435
435
  if (config.widgets.views?.widget) {
@@ -123,6 +123,19 @@ body.subsite-mkh {
123
123
  margin: 2em 0 !important;
124
124
  }
125
125
 
126
+ .ui.inverted.button.back-to-map {
127
+ margin-bottom: 2em;
128
+ box-shadow: 0px 0px 0px 2px @pineGreen inset !important;
129
+ color: @pineGreen;
130
+
131
+ &:hover,
132
+ &:active,
133
+ &:focus,
134
+ &:focus-visible {
135
+ background-color: @pineGreen;
136
+ }
137
+ }
138
+
126
139
  .column > .ui.segment {
127
140
  background-color: #fff !important;
128
141
  }
@@ -1,29 +0,0 @@
1
- import React from 'react';
2
- import { SidebarPortal } from '@plone/volto/components';
3
- import InlineForm from '@plone/volto/components/manage/Form/InlineForm';
4
- import schema from './schema';
5
- import View from './View';
6
-
7
- const Edit = (props) => {
8
- return (
9
- <>
10
- <View {...props} mode="edit" />
11
-
12
- <SidebarPortal selected={props.selected}>
13
- <InlineForm
14
- schema={schema}
15
- title={schema.title}
16
- onChangeField={(id, value) => {
17
- props.onChangeBlock(props.block, {
18
- ...props.data,
19
- [id]: value,
20
- });
21
- }}
22
- formData={props.data}
23
- />
24
- </SidebarPortal>
25
- </>
26
- );
27
- };
28
-
29
- export default Edit;
@@ -1,87 +0,0 @@
1
- import React from 'react';
2
- import { UniversalLink } from '@plone/volto/components';
3
-
4
- // {
5
- // "feature": {
6
- // "OBJECTID": 39,
7
- // "CNTR_CODE": "PL",
8
- // "CNTR_NAME": "Poland",
9
- // "NUTS_ID": "PL9",
10
- // "NUTS_Name_Excel": "Mazovia (Mazowieckie)",
11
- // "NAME_LATN": "Makroregion województwo mazowieckie",
12
- // "NUTS_NAME": "Makroregion województwo mazowieckie",
13
- // "LEVEL_CODE": "NUTS 1",
14
- // "Comments": null,
15
- // "CNTR_FLAG": "https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/4.1.4/flags/4x3/pl.svg",
16
- // "BIOGEO_REG_CODE": "Continental",
17
- // "BIOGEO_REG_NAME": "Continental Bio-geographical Region",
18
- // "_maxOverlap": 35559453062.672485,
19
- // "BIOGEO_NUTS_AREA": "100",
20
- // "SHAPE_Length": 1473687.3485873593,
21
- // "SHAPE_Area": 35559453062.672424
22
- // }
23
- // }
24
-
25
- const NutsRegion = ({ feature }) => {
26
- const fields = [
27
- ['Name', 'NUTS_NAME'],
28
- ['Country', 'CNTR_NAME'],
29
- ['NUTS level', 'LEVEL_CODE'],
30
- ['NUTS ID', 'NUTS_ID'],
31
- ['Bioregion', 'BIOGEO_REG_NAME'],
32
- ['Area', 'SHAPE_Area'],
33
- ];
34
- return <FieldsDisplay feature={feature} fields={fields} />;
35
- };
36
-
37
- const FieldsDisplay = ({ feature, fields }) => (
38
- <dl className="feature-info">
39
- {fields.map(([label, name]) => (
40
- <div key={name}>
41
- <dt>{label}</dt>
42
- <dd>{feature[name]}</dd>
43
- </div>
44
- ))}
45
- </dl>
46
- );
47
-
48
- // {
49
- // "feature": {
50
- // "OBJECTID": 61,
51
- // "CNTR_NAME": "Lithuania",
52
- // "CNTR_CODE": "LT",
53
- // "LEVEL_CODE": "LAU",
54
- // "GISCO_ID": "LT_27",
55
- // "LAU_ID": "27",
56
- // "LAU_NAME": "Panevėžio miesto savivaldybė",
57
- // "LAU_Name_Excel": "Panevėžys",
58
- // "Aggregated": "*",
59
- // "Value0": null,
60
- // "CNTR_FLAG": "https://cdnjs.cloudflare.com/ajax/libs/flag-icon-css/4.1.4/flags/4x3/lt.svg"
61
- // }
62
- // }
63
-
64
- const City = ({ feature }) => {
65
- const fields = [
66
- ['Name', 'LAU_NAME'],
67
- ['Country', 'CNTR_NAME'],
68
- ['Level', 'LEVEL_CODE'],
69
- ['GISCO ID', 'GISCO_ID'],
70
- ];
71
- return <FieldsDisplay feature={feature} fields={fields} />;
72
- };
73
-
74
- export default function FeatureDisplay({ feature }) {
75
- return feature ? (
76
- <div>
77
- {feature.NUTS_ID ? (
78
- <NutsRegion feature={feature} />
79
- ) : (
80
- <City feature={feature} />
81
- )}
82
- <UniversalLink href={`/en/mkh/${feature.NUTS_ID || feature.GISCO_ID}`}>
83
- Visit
84
- </UniversalLink>
85
- </div>
86
- ) : null;
87
- }
@@ -1,56 +0,0 @@
1
- import React from 'react';
2
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
3
- import { useMapContext } from '@eeacms/volto-openlayers-map/api';
4
-
5
- export default function FeatureInteraction({ onFeatureSelect }) {
6
- const { map } = useMapContext();
7
-
8
- const selected = React.useMemo(
9
- () =>
10
- new ol.style.Style({
11
- fill: new ol.style.Fill({
12
- color: '#cccccc',
13
- }),
14
- stroke: new ol.style.Stroke({
15
- color: 'rgba(255, 0, 0, 0.7)',
16
- width: 2,
17
- }),
18
- }),
19
- [],
20
- );
21
-
22
- const selectStyle = React.useCallback(
23
- (feature) => {
24
- const color = feature.get('COLOR') || '#eeeeee';
25
- selected.getFill().setColor(color);
26
- return selected;
27
- },
28
- [selected],
29
- );
30
-
31
- React.useEffect(() => {
32
- if (!map) return;
33
- const select = new ol.interaction.Select({
34
- condition: ol.condition.click,
35
- style: selectStyle,
36
- });
37
- map.addInteraction(select);
38
- select.on('select', function (e) {
39
- const features = e.target.getFeatures().getArray();
40
- features.forEach((feature) => {
41
- onFeatureSelect(feature.values_);
42
- });
43
- // if (!features.length) onFeatureSelect(null);
44
- });
45
-
46
- map.on('pointermove', (e) => {
47
- const pixel = map.getEventPixel(e.originalEvent);
48
- const hit = map.hasFeatureAtPixel(pixel);
49
- map.getViewport().style.cursor = hit ? 'pointer' : '';
50
- });
51
-
52
- return () => map.removeInteraction(select);
53
- }, [map, selectStyle, onFeatureSelect]);
54
-
55
- return null;
56
- }
@@ -1,80 +0,0 @@
1
- import React from 'react';
2
- import { useMapContext } from '@eeacms/volto-openlayers-map/api';
3
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
4
- import FeatureDisplay from './FeatureDisplay';
5
- import { usePrevious } from '@plone/volto/helpers/Utils/usePrevious';
6
-
7
- const isCluster = (features) => {
8
- return features.length > 1 ? true : features[0].values_?.features?.length > 1;
9
- };
10
-
11
- export default function InfoOverlay({
12
- selectedFeature,
13
- onFeatureSelect,
14
- layerId,
15
- hasCusters = false,
16
- }) {
17
- const { map } = useMapContext();
18
- const [tooltip, setTooltipRef] = React.useState();
19
- const [showTooltip, setShowTooltip] = React.useState();
20
-
21
- const prevLayerId = usePrevious(layerId);
22
-
23
- const [isClient, setIsClient] = React.useState(false);
24
- React.useEffect(() => setIsClient(true), []);
25
-
26
- React.useEffect(() => {
27
- if (prevLayerId && layerId !== prevLayerId) {
28
- setShowTooltip(false);
29
- }
30
- }, [layerId, prevLayerId]);
31
-
32
- React.useEffect(() => {
33
- if (!(map && tooltip)) return;
34
-
35
- const overlay = new ol.Overlay({
36
- element: document.getElementById('popup-overlay'),
37
- positioning: 'bottom-center',
38
- offset: [10, -10],
39
- stopEvent: false,
40
- });
41
- map.addOverlay(overlay);
42
-
43
- function handler(evt) {
44
- const coordinate = evt.coordinate;
45
- const { pixel, target } = evt;
46
- const features = target.getFeaturesAtPixel(pixel);
47
-
48
- if (features.length && (hasCusters ? !isCluster(features) : true)) {
49
- overlay.setPosition(coordinate);
50
- setShowTooltip(true);
51
- } else {
52
- // handle a click in an overlay popup
53
- if (evt.originalEvent.target.tagName === 'A') return;
54
- setShowTooltip(false);
55
- onFeatureSelect(null);
56
- }
57
- }
58
-
59
- map.on('click', handler);
60
-
61
- return () => {
62
- map.un('click', handler);
63
- map.removeOverlay(overlay);
64
- };
65
- }, [map, tooltip, onFeatureSelect, hasCusters]);
66
-
67
- return isClient ? (
68
- <div
69
- id="popup-overlay"
70
- style={{
71
- position: 'absolute',
72
- zIndex: 1,
73
- visibility: showTooltip ? 'visible' : 'hidden',
74
- }}
75
- ref={setTooltipRef}
76
- >
77
- {selectedFeature ? <FeatureDisplay feature={selectedFeature} /> : null}
78
- </div>
79
- ) : null;
80
- }