From 34162c0c2a49cb2085f3296bca38249417bba301 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 23 May 2024 13:11:31 -0400 Subject: [PATCH 001/350] basic 2d map --- src/app.jsx | 3 ++ src/pages/dashboard/index.js | 61 ++++++++++++++++++++++++++++++++ src/pages/dashboard/selectors.js | 35 ++++++++++++++++++ src/router.ts | 5 +++ 4 files changed, 104 insertions(+) create mode 100644 src/pages/dashboard/index.js create mode 100644 src/pages/dashboard/selectors.js diff --git a/src/app.jsx b/src/app.jsx index cd31b4268..bbabbff37 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -31,6 +31,7 @@ const FeaturedGlobe = loadable(() => import('pages/featured-globe')); const NationalReportCard = loadable(() => import('pages/nrc')); const NationalReportCardLanding = loadable(() => import('pages/nrc-landing')); const AreaOfInterest = loadable(() => import('pages/aoi')); +const DashboardComponent = loadable(() => import('pages/dashboard')); const mapStateToProps = ({ location }) => ({ route: location.routesMap[location.type], @@ -62,6 +63,8 @@ function AppLayout(props) { ); case 'aoi': return ; + case 'dashboard': + return ; default: return isMobile ? : ; } diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js new file mode 100644 index 000000000..df5ca8c5a --- /dev/null +++ b/src/pages/dashboard/index.js @@ -0,0 +1,61 @@ +import React, { useEffect, useState } from 'react'; +import { connect } from 'react-redux'; + +import { loadModules } from 'esri-loader'; + +import * as urlActions from 'actions/url-actions'; + +import Logo from 'components/half-earth-logo'; + +import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; + +import uiStyles from 'styles/ui.module.scss'; + +import mapStateToProps from './selectors'; + +const actions = { ...urlActions }; + +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + +function DashboardComponent(props) { + const [map, setMap] = useState(null); + const [view, setView] = useState(null); + + useEffect(() => { + loadModules(['esri/Map', 'esri/views/MapView'], { + url: `https://js.arcgis.com/${API_VERSION}`, + }) + .then(([Map, MapView]) => { + const myMap = new Map({ + basemap: SATELLITE_BASEMAP_LAYER, + }); + + const myView = new MapView({ + map: myMap, + center: [-118.805, 34.027], // Longitude, latitude + zoom: 13, // Zoom level + container: 'map', + }); + setView(myView); + setMap(myMap); + console.log(map); + console.log(view); + }) + .catch((err) => { + console.error(err); + }); + }, []); + + console.log(props); + return ( + <> + +
+ + ); +} + +export default connect(mapStateToProps, actions)(DashboardComponent); diff --git a/src/pages/dashboard/selectors.js b/src/pages/dashboard/selectors.js new file mode 100644 index 000000000..e6865f665 --- /dev/null +++ b/src/pages/dashboard/selectors.js @@ -0,0 +1,35 @@ +import { createSelector, createStructuredSelector } from 'reselect'; + +const selectCountryIso = ({ location }) => location.payload.iso.toUpperCase(); +const selectCountriesData = ({ countryData }) => + countryData && countryData.data; + +const getCountryData = createSelector( + [selectCountriesData, selectCountryIso], + (countriesData, countryISO) => { + if (!countriesData || !countryISO) { + return null; + } + return countriesData[countryISO]; + } +); + +const getCountryName = createSelector([getCountryData], (countryData) => { + if (!countryData) { + return null; + } + return countryData.NAME_0; +}); + +const getCountryId = createSelector([getCountryData], (countryData) => { + if (!countryData) { + return null; + } + return countryData.OBJECTID; +}); + +export default createStructuredSelector({ + countryISO: selectCountryIso, + countryId: getCountryId, + countryName: getCountryName, +}); diff --git a/src/router.ts b/src/router.ts index deac323f4..13fa460e5 100644 --- a/src/router.ts +++ b/src/router.ts @@ -11,6 +11,7 @@ export const NATIONAL_REPORT_CARD_LANDING = 'location/NATIONAL_REPORT_CARD_LANDING'; export const AREA_OF_INTEREST = 'location/AREA_OF_INTEREST'; export const MAP_IFRAME = 'location/MAP_IFRAME'; +export const DASHBOARD = 'location/DASHBOARD'; export const routes: RoutesMap<{ path: string; page?: string }> = { [LANDING]: { @@ -37,6 +38,10 @@ export const routes: RoutesMap<{ path: string; page?: string }> = { path: '/aoi/:id?', page: 'aoi', }, + [DASHBOARD]: { + path: '/dashboard/:iso', + page: 'dashboard', + }, [NOT_FOUND]: { path: '/404', thunk: (dispatch) => dispatch(redirect({ type: LANDING })), From 2f8c342260e15232734d4b15eeeaac41c272e60b Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 28 May 2024 10:38:44 -0400 Subject: [PATCH 002/350] display map with click --- src/pages/dashboard/index.js | 188 ++++++++++++++++++++++++++++++----- 1 file changed, 164 insertions(+), 24 deletions(-) diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index df5ca8c5a..7a7568700 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect } from 'react'; import { connect } from 'react-redux'; import { loadModules } from 'esri-loader'; @@ -7,7 +7,7 @@ import * as urlActions from 'actions/url-actions'; import Logo from 'components/half-earth-logo'; -import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; +// import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; import uiStyles from 'styles/ui.module.scss'; @@ -17,30 +17,170 @@ const actions = { ...urlActions }; const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; +const mapViewConstraints = { + minZoom: 3, + rotationEnabled: false, + snapToZoom: false, + minScale: 147914381, +}; + function DashboardComponent(props) { - const [map, setMap] = useState(null); - const [view, setView] = useState(null); + // const [map, setMap] = useState(null); + // const [view, setView] = useState(null); + + const highlightCountry = async (query, zoomGeometry, layers, view) => { + const { countries, graphicsLayer, worldImagery, groupLayer } = layers; + console.log(layers); + // country symbol - when user clicks on a country + // we will query the country from the countries featurelayer + // add the country feature to the graphics layer. + const symbol = { + type: 'simple-fill', + color: 'rgba(255, 255, 255, 1)', + outline: null, + }; + + // query the countries layer for a country that intersects the clicked point + const { + features: [feature], + } = await countries.queryFeatures(query); + // user clicked on a country and the feature is returned + if (feature) { + console.log('feature', feature); + graphicsLayer.graphics.removeAll(); + feature.symbol = symbol; + // add the country to the graphics layer + graphicsLayer.graphics.add(feature); + // zoom to the highlighted country + view.goTo( + { + target: zoomGeometry, + extent: feature.geometry.clone(), + }, + { duration: 1000 } + ); + // blur the world imagery basemap so that the clicked country can be highlighted + worldImagery.effect = 'blur(8px) brightness(1.2) grayscale(0.8)'; + // set the group layer opacity to 1 + // also increase the layer brightness and add drop-shadow to make the clicked country stand out. + groupLayer.effect = 'brightness(1.5) drop-shadow(0, 0px, 12px)'; + groupLayer.opacity = 1; + } + }; useEffect(() => { - loadModules(['esri/Map', 'esri/views/MapView'], { - url: `https://js.arcgis.com/${API_VERSION}`, - }) - .then(([Map, MapView]) => { - const myMap = new Map({ - basemap: SATELLITE_BASEMAP_LAYER, - }); - - const myView = new MapView({ - map: myMap, - center: [-118.805, 34.027], // Longitude, latitude - zoom: 13, // Zoom level - container: 'map', - }); - setView(myView); - setMap(myMap); - console.log(map); - console.log(view); - }) + loadModules( + [ + 'esri/Map', + 'esri/views/MapView', + 'esri/layers/TileLayer', + // 'esri/Graphic', + 'esri/layers/FeatureLayer', + 'esri/layers/GraphicsLayer', + 'esri/layers/GroupLayer', + ], + { + url: `https://js.arcgis.com/${API_VERSION}`, + } + ) + .then( + ([ + Map, + MapView, + TileLayer, + // Graphic, + FeatureLayer, + GraphicsLayer, + GroupLayer, + ]) => { + const worldImagery = new TileLayer({ + portalItem: { + id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery + }, + }); + + worldImagery.when(() => { + worldImagery.sublayers.forEach((layer) => { + if (layer.popupEnabled === true) { + layer.popupEnabled = false; + } + }); + }); + + const countries = new FeatureLayer({ + portalItem: { + id: '53a1e68de7e4499cad77c80daba46a94', + }, + }); + + // clicked country feature will be added to this layer + const graphicsLayer = new GraphicsLayer({ + blendMode: 'destination-in', + title: 'layer', + }); + + const tileLayer = new TileLayer({ + portalItem: { + // bottom layer in the group layer + id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery + }, + }); + tileLayer.when(() => { + tileLayer.sublayers.forEach((layer) => { + if (layer.popupEnabled === true) { + layer.popupEnabled = false; + } + }); + }); + + // this grouplayer has two layers + // destination-in blendMode set on the graphics layer + // country from the world imagery layer will show when user clicks on a country + const groupLayer = new GroupLayer({ + layers: [ + tileLayer, + // world imagery layer will show where it overlaps with the graphicslayer + graphicsLayer, + ], + opacity: 0, // initially this layer will be transparent + }); + + const layers = { countries, worldImagery, graphicsLayer, groupLayer }; + + const myMap = new Map({ + // basemap: SATELLITE_BASEMAP_LAYER, + layers: [worldImagery, groupLayer], + }); + + const myView = new MapView({ + map: myMap, + zoom: 6, // Zoom level + center: [2, 46], + popup: null, + constraints: mapViewConstraints, + container: 'map', + }); + + myView.when(async () => { + const query = { + geometry: myView.center, + returnGeometry: true, + outFields: ['*'], + }; + await highlightCountry(query, myView.center, layers, myView); + }); + + // listen to the view's click event + myView.on('click', async (event) => { + const query = { + geometry: myView.toMap(event), + returnGeometry: true, + outFields: ['*'], + }; + await highlightCountry(query, query.geometry, layers, myView); + }); + } + ) .catch((err) => { console.error(err); }); @@ -52,7 +192,7 @@ function DashboardComponent(props) {
); From 60049c213ed4a2b85ef3232c764d6fb59839aa04 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 30 May 2024 14:24:00 -0400 Subject: [PATCH 003/350] updated and cleaned up dashboard load --- src/components/map-view/component.jsx | 34 +++ src/components/map-view/index.js | 245 +++++++++++++++++++ src/components/map-view/selectors.js | 0 src/containers/views/dashboard/component.jsx | 16 ++ src/containers/views/dashboard/index.js | 9 + src/pages/dashboard/component.jsx | 20 ++ src/pages/dashboard/index.js | 198 +-------------- 7 files changed, 328 insertions(+), 194 deletions(-) create mode 100644 src/components/map-view/component.jsx create mode 100644 src/components/map-view/index.js create mode 100644 src/components/map-view/selectors.js create mode 100644 src/containers/views/dashboard/component.jsx create mode 100644 src/containers/views/dashboard/index.js create mode 100644 src/pages/dashboard/component.jsx diff --git a/src/components/map-view/component.jsx b/src/components/map-view/component.jsx new file mode 100644 index 000000000..6e8079514 --- /dev/null +++ b/src/components/map-view/component.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +export default function ViewComponent(props) { + const { map, view, mapName, mapId, children, loadState = 'loaded' } = props; + // if (loadState === 'loading') { + // return ( + // <> + //
+ // + // + // ); + // } + if (loadState === 'loaded') { + return ( +
+ {React.Children.map(children || null, (child, i) => { + return ( + child && ( + // eslint-disable-next-line react/no-array-index-key + + ) + ); + })} +
+ ); + } +} diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js new file mode 100644 index 000000000..926138b19 --- /dev/null +++ b/src/components/map-view/index.js @@ -0,0 +1,245 @@ +import React, { useEffect, useState } from 'react'; + +import { loadModules } from 'esri-loader'; + +import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; + +import Component from './component'; + +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + +const mapViewConstraints = { + minZoom: 3, + rotationEnabled: false, + snapToZoom: false, + minScale: 147914381, +}; + +function ViewContainer(props) { + const { mapId, mapName, onViewLoad } = props; + + const [map, setMap] = useState(null); + const [view, setView] = useState(null); + const loaderOptions = { + url: `https://js.arcgis.com/${API_VERSION}`, + }; + + useEffect(() => { + loadModules(['esri/Map', 'esri/layers/FeatureLayer'], loaderOptions) + .then(([Map, FeatureLayer]) => { + const countries = new FeatureLayer({ + portalItem: { + id: '53a1e68de7e4499cad77c80daba46a94', + }, + }); + + const flatMap = new Map({ + basemap: SATELLITE_BASEMAP_LAYER, + ground: { + surfaceColor: '#070710', + }, + layers: [countries], + }); + + setMap(flatMap); + // if (onMapLoad) { + // onMapLoad(flatMap); + // } + }) + .catch((err) => { + console.error(err); + }); + }, []); + + useEffect(() => { + if (map) { + loadModules(['esri/views/MapView'], loaderOptions) + .then(([MapView]) => { + const flatView = new MapView({ + map, + container: `map-container-${mapName || mapId}`, + zoom: 6, + center: [-3, 42], + popup: null, + constraints: mapViewConstraints, + }); + + setView(flatView); + }) + .catch((err) => { + console.error(err); + }); + } + }, [map]); + + useEffect(() => { + if (map && view) { + if (onViewLoad) { + onViewLoad(map, view); + } + } + }, [map, view]); + + return ; +} + +export default ViewContainer; + +// const [, setMap] = useState(null); +// // const [view, setView] = useState(null); + +// const highlightCountry = async (query, zoomGeometry, layers, view) => { +// const { countries, graphicsLayer, groupLayer } = layers; +// // country symbol - when user clicks on a country +// // we will query the country from the countries featurelayer +// // add the country feature to the graphics layer. +// const symbol = { +// type: 'simple-fill', +// color: 'rgba(255, 255, 255, 1)', +// outline: null, +// }; + +// // query the countries layer for a country that intersects the clicked point +// const { +// features: [feature], +// } = await countries.queryFeatures(query); +// // user clicked on a country and the feature is returned +// if (feature) { +// graphicsLayer.graphics.removeAll(); +// feature.symbol = symbol; +// // add the country to the graphics layer +// graphicsLayer.graphics.add(feature); +// // zoom to the highlighted country +// view.goTo( +// { +// target: zoomGeometry, +// extent: feature.geometry.clone(), +// }, +// { duration: 1000 } +// ); +// // set the group layer opacity to 1 +// // also increase the layer brightness and add drop-shadow to make the clicked country stand out. +// groupLayer.effect = 'brightness(1.5) drop-shadow(0, 0px, 12px)'; +// groupLayer.opacity = 1; +// } +// }; + +// useEffect(() => { +// loadModules( +// [ +// 'esri/Map', +// 'esri/views/MapView', +// 'esri/layers/TileLayer', +// // 'esri/Graphic', +// 'esri/layers/FeatureLayer', +// 'esri/layers/GraphicsLayer', +// 'esri/layers/GroupLayer', +// ], +// { +// url: `https://js.arcgis.com/${API_VERSION}`, +// } +// ) +// .then( +// ([ +// Map, +// MapView, +// TileLayer, +// // Graphic, +// FeatureLayer, +// GraphicsLayer, +// GroupLayer, +// ]) => { +// const worldImagery = new TileLayer({ +// portalItem: { +// id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery +// }, +// }); + +// worldImagery.when(() => { +// worldImagery.sublayers.forEach((layer) => { +// if (layer.popupEnabled === true) { +// layer.popupEnabled = false; +// } +// }); +// }); + +// const countries = new FeatureLayer({ +// portalItem: { +// id: '53a1e68de7e4499cad77c80daba46a94', +// }, +// }); + +// // clicked country feature will be added to this layer +// const graphicsLayer = new GraphicsLayer({ +// blendMode: 'destination-in', +// title: 'layer', +// }); + +// const tileLayer = new TileLayer({ +// portalItem: { +// // bottom layer in the group layer +// id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery +// }, +// }); +// tileLayer.when(() => { +// tileLayer.sublayers.forEach((layer) => { +// if (layer.popupEnabled === true) { +// layer.popupEnabled = false; +// } +// }); +// }); + +// // this grouplayer has two layers +// // destination-in blendMode set on the graphics layer +// // country from the world imagery layer will show when user clicks on a country +// const groupLayer = new GroupLayer({ +// layers: [ +// tileLayer, +// // world imagery layer will show where it overlaps with the graphicslayer +// graphicsLayer, +// ], +// opacity: 0, // initially this layer will be transparent +// }); + +// const layers = { countries, graphicsLayer, groupLayer }; + +// const myMap = new Map({ +// // basemap: SATELLITE_BASEMAP_LAYER, +// layers: [worldImagery, countries, groupLayer], +// }); + +// setMap(myMap); + +// const myView = new MapView({ +// map: myMap, +// zoom: 6, // Zoom level +// center: [-3, 42], +// popup: null, +// constraints: mapViewConstraints, +// container: 'map', +// }); + +// myView.when(async () => { +// const query = { +// geometry: myView.center, +// returnGeometry: true, +// outFields: ['*'], +// }; +// await highlightCountry(query, myView.center, layers, myView); +// }); + +// // listen to the view's click event +// myView.on('click', async (event) => { +// const query = { +// geometry: myView.toMap(event), +// returnGeometry: true, +// outFields: ['*'], +// }; +// await highlightCountry(query, query.geometry, layers, myView); +// }); +// } +// ) +// .catch((err) => { +// console.error(err); +// }); +// }, []); diff --git a/src/components/map-view/selectors.js b/src/components/map-view/selectors.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/containers/views/dashboard/component.jsx b/src/containers/views/dashboard/component.jsx new file mode 100644 index 000000000..7ca796da2 --- /dev/null +++ b/src/containers/views/dashboard/component.jsx @@ -0,0 +1,16 @@ +import React from 'react'; + +import MapView from '../../../components/map-view'; + +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + +function DashboardViewComponent() { + return ( + + ); +} + +export default DashboardViewComponent; diff --git a/src/containers/views/dashboard/index.js b/src/containers/views/dashboard/index.js new file mode 100644 index 000000000..ef0731491 --- /dev/null +++ b/src/containers/views/dashboard/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import Component from './component'; + +function DashboardView(props) { + return ; +} + +export default DashboardView; diff --git a/src/pages/dashboard/component.jsx b/src/pages/dashboard/component.jsx new file mode 100644 index 000000000..9e002d34f --- /dev/null +++ b/src/pages/dashboard/component.jsx @@ -0,0 +1,20 @@ +import React from 'react'; + +import cx from 'classnames'; + +import Logo from 'components/half-earth-logo'; + +import uiStyles from 'styles/ui.module.scss'; + +import DashboardView from '../../containers/views/dashboard'; + +function DashboardPageComponent(props) { + return ( + <> + + + + ); +} + +export default DashboardPageComponent; diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index 7a7568700..152bae747 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -1,201 +1,11 @@ -import React, { useEffect } from 'react'; +import React from 'react'; import { connect } from 'react-redux'; -import { loadModules } from 'esri-loader'; - -import * as urlActions from 'actions/url-actions'; - -import Logo from 'components/half-earth-logo'; - -// import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; - -import uiStyles from 'styles/ui.module.scss'; - +import Component from './component'; import mapStateToProps from './selectors'; -const actions = { ...urlActions }; - -const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; - -const mapViewConstraints = { - minZoom: 3, - rotationEnabled: false, - snapToZoom: false, - minScale: 147914381, -}; - function DashboardComponent(props) { - // const [map, setMap] = useState(null); - // const [view, setView] = useState(null); - - const highlightCountry = async (query, zoomGeometry, layers, view) => { - const { countries, graphicsLayer, worldImagery, groupLayer } = layers; - console.log(layers); - // country symbol - when user clicks on a country - // we will query the country from the countries featurelayer - // add the country feature to the graphics layer. - const symbol = { - type: 'simple-fill', - color: 'rgba(255, 255, 255, 1)', - outline: null, - }; - - // query the countries layer for a country that intersects the clicked point - const { - features: [feature], - } = await countries.queryFeatures(query); - // user clicked on a country and the feature is returned - if (feature) { - console.log('feature', feature); - graphicsLayer.graphics.removeAll(); - feature.symbol = symbol; - // add the country to the graphics layer - graphicsLayer.graphics.add(feature); - // zoom to the highlighted country - view.goTo( - { - target: zoomGeometry, - extent: feature.geometry.clone(), - }, - { duration: 1000 } - ); - // blur the world imagery basemap so that the clicked country can be highlighted - worldImagery.effect = 'blur(8px) brightness(1.2) grayscale(0.8)'; - // set the group layer opacity to 1 - // also increase the layer brightness and add drop-shadow to make the clicked country stand out. - groupLayer.effect = 'brightness(1.5) drop-shadow(0, 0px, 12px)'; - groupLayer.opacity = 1; - } - }; - - useEffect(() => { - loadModules( - [ - 'esri/Map', - 'esri/views/MapView', - 'esri/layers/TileLayer', - // 'esri/Graphic', - 'esri/layers/FeatureLayer', - 'esri/layers/GraphicsLayer', - 'esri/layers/GroupLayer', - ], - { - url: `https://js.arcgis.com/${API_VERSION}`, - } - ) - .then( - ([ - Map, - MapView, - TileLayer, - // Graphic, - FeatureLayer, - GraphicsLayer, - GroupLayer, - ]) => { - const worldImagery = new TileLayer({ - portalItem: { - id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery - }, - }); - - worldImagery.when(() => { - worldImagery.sublayers.forEach((layer) => { - if (layer.popupEnabled === true) { - layer.popupEnabled = false; - } - }); - }); - - const countries = new FeatureLayer({ - portalItem: { - id: '53a1e68de7e4499cad77c80daba46a94', - }, - }); - - // clicked country feature will be added to this layer - const graphicsLayer = new GraphicsLayer({ - blendMode: 'destination-in', - title: 'layer', - }); - - const tileLayer = new TileLayer({ - portalItem: { - // bottom layer in the group layer - id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery - }, - }); - tileLayer.when(() => { - tileLayer.sublayers.forEach((layer) => { - if (layer.popupEnabled === true) { - layer.popupEnabled = false; - } - }); - }); - - // this grouplayer has two layers - // destination-in blendMode set on the graphics layer - // country from the world imagery layer will show when user clicks on a country - const groupLayer = new GroupLayer({ - layers: [ - tileLayer, - // world imagery layer will show where it overlaps with the graphicslayer - graphicsLayer, - ], - opacity: 0, // initially this layer will be transparent - }); - - const layers = { countries, worldImagery, graphicsLayer, groupLayer }; - - const myMap = new Map({ - // basemap: SATELLITE_BASEMAP_LAYER, - layers: [worldImagery, groupLayer], - }); - - const myView = new MapView({ - map: myMap, - zoom: 6, // Zoom level - center: [2, 46], - popup: null, - constraints: mapViewConstraints, - container: 'map', - }); - - myView.when(async () => { - const query = { - geometry: myView.center, - returnGeometry: true, - outFields: ['*'], - }; - await highlightCountry(query, myView.center, layers, myView); - }); - - // listen to the view's click event - myView.on('click', async (event) => { - const query = { - geometry: myView.toMap(event), - returnGeometry: true, - outFields: ['*'], - }; - await highlightCountry(query, query.geometry, layers, myView); - }); - } - ) - .catch((err) => { - console.error(err); - }); - }, []); - - console.log(props); - return ( - <> - -
- - ); + return ; } -export default connect(mapStateToProps, actions)(DashboardComponent); +export default connect(mapStateToProps, null)(DashboardComponent); From a5d8d3e68fdf88326216e4851832c6146e1ab904 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 4 Jun 2024 10:46:58 -0400 Subject: [PATCH 004/350] dashboard child components --- src/components/map-view/index.js | 255 +++++++----------- .../sidebars/dashboard-sidebar/component.jsx | 25 ++ .../data-layers/component.jsx | 7 + .../dashboard-sidebar/data-layers/index.js | 9 + .../sidebars/dashboard-sidebar/index.js | 11 + .../sidebars/dashboard-sidebar/selectors.js | 0 .../species-info/component.jsx | 26 ++ .../dashboard-sidebar/species-info/index.js | 9 + .../species-info/styles.module.scss | 47 ++++ .../dashboard-sidebar/styles.module.scss | 56 ++++ src/containers/views/dashboard/component.jsx | 5 +- 11 files changed, 287 insertions(+), 163 deletions(-) create mode 100644 src/containers/sidebars/dashboard-sidebar/component.jsx create mode 100644 src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx create mode 100644 src/containers/sidebars/dashboard-sidebar/data-layers/index.js create mode 100644 src/containers/sidebars/dashboard-sidebar/index.js create mode 100644 src/containers/sidebars/dashboard-sidebar/selectors.js create mode 100644 src/containers/sidebars/dashboard-sidebar/species-info/component.jsx create mode 100644 src/containers/sidebars/dashboard-sidebar/species-info/index.js create mode 100644 src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss create mode 100644 src/containers/sidebars/dashboard-sidebar/styles.module.scss diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js index 926138b19..49a8a8f06 100644 --- a/src/components/map-view/index.js +++ b/src/components/map-view/index.js @@ -20,25 +20,97 @@ function ViewContainer(props) { const [map, setMap] = useState(null); const [view, setView] = useState(null); + const [countryLayer, setCountryLayer] = useState(null); + const [graphicsLayer, setGraphicsLayer] = useState(null); + const [groupLayer, setGroupLayer] = useState(null); + const loaderOptions = { url: `https://js.arcgis.com/${API_VERSION}`, }; + const highlightCountry = async (query, zoomGeometry, flatView) => { + // country symbol - when user clicks on a country + // we will query the country from the countries featurelayer + // add the country feature to the graphics layer. + const symbol = { + type: 'simple-fill', + color: 'rgba(255, 255, 255, 1)', + outline: null, + }; + + // query the countries layer for a country that intersects the clicked point + const { + features: [feature], + } = await countryLayer.queryFeatures(query); + // user clicked on a country and the feature is returned + if (feature) { + graphicsLayer.graphics.removeAll(); + feature.symbol = symbol; + // add the country to the graphics layer + graphicsLayer.graphics.add(feature); + // zoom to the highlighted country + flatView.goTo( + { + target: zoomGeometry, + extent: feature.geometry.clone(), + }, + { duration: 1000 } + ); + // set the group layer opacity to 1 + // also increase the layer brightness and add drop-shadow to make the clicked country stand out. + groupLayer.effect = 'brightness(1.5) drop-shadow(0, 0px, 12px)'; + groupLayer.opacity = 1; + } + }; + useEffect(() => { - loadModules(['esri/Map', 'esri/layers/FeatureLayer'], loaderOptions) - .then(([Map, FeatureLayer]) => { + loadModules( + [ + 'esri/Map', + 'esri/layers/FeatureLayer', + 'esri/layers/GraphicsLayer', + 'esri/layers/GroupLayer', + 'esri/layers/TileLayer', + ], + loaderOptions + ) + .then(([Map, FeatureLayer, GraphicsLayer, GroupLayer, TileLayer]) => { const countries = new FeatureLayer({ portalItem: { id: '53a1e68de7e4499cad77c80daba46a94', }, }); + setCountryLayer(countries); + + const graphics = new GraphicsLayer({ + blendMode: 'destination-in', + title: 'layer', + }); + setGraphicsLayer(graphics); + + const tileLayer = new TileLayer({ + portalItem: { + // bottom layer in the group layer + id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery + }, + }); + + const group = new GroupLayer({ + layers: [ + tileLayer, + // world imagery layer will show where it overlaps with the graphicslayer + graphics, + ], + opacity: 0, // initially this layer will be transparent + }); + setGroupLayer(group); const flatMap = new Map({ basemap: SATELLITE_BASEMAP_LAYER, ground: { surfaceColor: '#070710', }, - layers: [countries], + layers: [countries, group], }); setMap(flatMap); @@ -64,6 +136,24 @@ function ViewContainer(props) { constraints: mapViewConstraints, }); + flatView.when(async () => { + const query = { + geometry: flatView.center, + returnGeometry: true, + outFields: ['*'], + }; + await highlightCountry(query, flatView.center, flatView); + }); + + flatView.on('click', async (event) => { + const query = { + geometry: flatView.toMap(event), + returnGeometry: true, + outFields: ['*'], + }; + await highlightCountry(query, query.geometry, flatView); + }); + setView(flatView); }) .catch((err) => { @@ -84,162 +174,3 @@ function ViewContainer(props) { } export default ViewContainer; - -// const [, setMap] = useState(null); -// // const [view, setView] = useState(null); - -// const highlightCountry = async (query, zoomGeometry, layers, view) => { -// const { countries, graphicsLayer, groupLayer } = layers; -// // country symbol - when user clicks on a country -// // we will query the country from the countries featurelayer -// // add the country feature to the graphics layer. -// const symbol = { -// type: 'simple-fill', -// color: 'rgba(255, 255, 255, 1)', -// outline: null, -// }; - -// // query the countries layer for a country that intersects the clicked point -// const { -// features: [feature], -// } = await countries.queryFeatures(query); -// // user clicked on a country and the feature is returned -// if (feature) { -// graphicsLayer.graphics.removeAll(); -// feature.symbol = symbol; -// // add the country to the graphics layer -// graphicsLayer.graphics.add(feature); -// // zoom to the highlighted country -// view.goTo( -// { -// target: zoomGeometry, -// extent: feature.geometry.clone(), -// }, -// { duration: 1000 } -// ); -// // set the group layer opacity to 1 -// // also increase the layer brightness and add drop-shadow to make the clicked country stand out. -// groupLayer.effect = 'brightness(1.5) drop-shadow(0, 0px, 12px)'; -// groupLayer.opacity = 1; -// } -// }; - -// useEffect(() => { -// loadModules( -// [ -// 'esri/Map', -// 'esri/views/MapView', -// 'esri/layers/TileLayer', -// // 'esri/Graphic', -// 'esri/layers/FeatureLayer', -// 'esri/layers/GraphicsLayer', -// 'esri/layers/GroupLayer', -// ], -// { -// url: `https://js.arcgis.com/${API_VERSION}`, -// } -// ) -// .then( -// ([ -// Map, -// MapView, -// TileLayer, -// // Graphic, -// FeatureLayer, -// GraphicsLayer, -// GroupLayer, -// ]) => { -// const worldImagery = new TileLayer({ -// portalItem: { -// id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery -// }, -// }); - -// worldImagery.when(() => { -// worldImagery.sublayers.forEach((layer) => { -// if (layer.popupEnabled === true) { -// layer.popupEnabled = false; -// } -// }); -// }); - -// const countries = new FeatureLayer({ -// portalItem: { -// id: '53a1e68de7e4499cad77c80daba46a94', -// }, -// }); - -// // clicked country feature will be added to this layer -// const graphicsLayer = new GraphicsLayer({ -// blendMode: 'destination-in', -// title: 'layer', -// }); - -// const tileLayer = new TileLayer({ -// portalItem: { -// // bottom layer in the group layer -// id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery -// }, -// }); -// tileLayer.when(() => { -// tileLayer.sublayers.forEach((layer) => { -// if (layer.popupEnabled === true) { -// layer.popupEnabled = false; -// } -// }); -// }); - -// // this grouplayer has two layers -// // destination-in blendMode set on the graphics layer -// // country from the world imagery layer will show when user clicks on a country -// const groupLayer = new GroupLayer({ -// layers: [ -// tileLayer, -// // world imagery layer will show where it overlaps with the graphicslayer -// graphicsLayer, -// ], -// opacity: 0, // initially this layer will be transparent -// }); - -// const layers = { countries, graphicsLayer, groupLayer }; - -// const myMap = new Map({ -// // basemap: SATELLITE_BASEMAP_LAYER, -// layers: [worldImagery, countries, groupLayer], -// }); - -// setMap(myMap); - -// const myView = new MapView({ -// map: myMap, -// zoom: 6, // Zoom level -// center: [-3, 42], -// popup: null, -// constraints: mapViewConstraints, -// container: 'map', -// }); - -// myView.when(async () => { -// const query = { -// geometry: myView.center, -// returnGeometry: true, -// outFields: ['*'], -// }; -// await highlightCountry(query, myView.center, layers, myView); -// }); - -// // listen to the view's click event -// myView.on('click', async (event) => { -// const query = { -// geometry: myView.toMap(event), -// returnGeometry: true, -// outFields: ['*'], -// }; -// await highlightCountry(query, query.geometry, layers, myView); -// }); -// } -// ) -// .catch((err) => { -// console.error(err); -// }); -// }, []); diff --git a/src/containers/sidebars/dashboard-sidebar/component.jsx b/src/containers/sidebars/dashboard-sidebar/component.jsx new file mode 100644 index 000000000..42dd2cf26 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/component.jsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import styles from './styles.module.scss'; + +import DataLayerContainer from './data-layers'; +import SpeciesInfoContainer from './species-info'; + +function DashboardSidebar() { + return ( +
+ + +
+
+ DL + BI + RA +
+ +
+
+ ); +} + +export default DashboardSidebar; diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx new file mode 100644 index 000000000..2ce39b4f3 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +function DataLayerComponent() { + return
DataLayerComponent
; +} + +export default DataLayerComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/index.js b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js new file mode 100644 index 000000000..a714d68ac --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import DataLayerComponent from './component'; + +function DataLayerContainer(props) { + return ; +} + +export default DataLayerContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/index.js b/src/containers/sidebars/dashboard-sidebar/index.js new file mode 100644 index 000000000..221f7cea5 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/index.js @@ -0,0 +1,11 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +import Component from './component.jsx'; +import mapStateToProps from './selectors'; + +function DashboardSidebarContainer() { + return ; +} + +export default connect(mapStateToProps, null)(DashboardSidebarContainer); diff --git a/src/containers/sidebars/dashboard-sidebar/selectors.js b/src/containers/sidebars/dashboard-sidebar/selectors.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/component.jsx b/src/containers/sidebars/dashboard-sidebar/species-info/component.jsx new file mode 100644 index 000000000..2e06d8427 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/species-info/component.jsx @@ -0,0 +1,26 @@ +import React from 'react'; + +import styles from './styles.module.scss'; + +function SpeciesInfoComponent() { + return ( +
+
+ species +
+ Hamlyns Monkey + Cercopithecus hamlyni + taxa +
+
+

+ The Hamlyns monkey (Cercopithecus hamlyni), also known as the owl-faced + monkey, is a species of Old World monkey that inhabits the bamboo and + primary rainforests of the Congo. This species is exceedingly rare and + known only from a few specimens; little is known about it. +

+
+ ); +} + +export default SpeciesInfoComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/index.js b/src/containers/sidebars/dashboard-sidebar/species-info/index.js new file mode 100644 index 000000000..2fbe9eeb4 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/species-info/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import SpeciesInfoComponent from './component'; + +function SpeciesInfoContainer(props) { + return ; +} + +export default SpeciesInfoContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss b/src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss new file mode 100644 index 000000000..ce425595a --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss @@ -0,0 +1,47 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.species{ + display: flex; + flex-direction: column; + gap: 15px; + background-color: #efefef; + + .title{ + display: flex; + gap: 10px; + + img{ + width: 130px; + height: 130px; + margin-top: 8px; + } + + .info{ + display: flex; + flex-direction: column; + gap: 5px; + + .commonName{ + font-weight: 700; + font-size: 24px; + } + + .taxa{ + font-style: italic; + font-size: 18px; + } + + img{ + width: 60px; + height: 60px; + } + } + + .description { + font-size: 14px; + } + } +} diff --git a/src/containers/sidebars/dashboard-sidebar/styles.module.scss b/src/containers/sidebars/dashboard-sidebar/styles.module.scss new file mode 100644 index 000000000..76ae53ffe --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/styles.module.scss @@ -0,0 +1,56 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +$sidebar-content-top: 180px; + +.sidebarContainer { + @include animationFunction($propertyToAnimate: all); + position: absolute; + height: calc(100vh - #{$nav-bar-height}); + width: calc(#{$sidebar-width} + 30px); + top: $nav-bar-height; + left: $site-gutter; + padding-bottom: $site-gutter; + padding-left: 5px; + + display: flex; + flex-direction: column; + gap: 10px; +} + +.container { + @extend %verticalScrollbar; + @include backdropBlur(); + position: absolute; + top: $sidebar-content-top; + left: $site-gutter; + display: flex; + flex-direction: column; + border: $sidebar-border; + border-radius: $sidebar-border-radius; + height: calc(100vh - #{$sidebar-content-top}); + width: $sidebar-width; + padding: $site-gutter; + z-index: $bring-to-front; +} + +.sidenav{ + display: flex; + height: 100%; + background: rgba(255, 255, 255, 0.4); + + .icons{ + display: flex; + flex-direction: column; + height: 100%; + border-right: 1px solid; + + span{ + display: inline-block; + width: 50px; + height: 50px; + } + } +} diff --git a/src/containers/views/dashboard/component.jsx b/src/containers/views/dashboard/component.jsx index 7ca796da2..5e5af8a19 100644 --- a/src/containers/views/dashboard/component.jsx +++ b/src/containers/views/dashboard/component.jsx @@ -1,6 +1,7 @@ import React from 'react'; import MapView from '../../../components/map-view'; +import DashboardSidebar from '../../sidebars/dashboard-sidebar/component'; const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; @@ -9,7 +10,9 @@ function DashboardViewComponent() { + > + + ); } From 3dcde8b7ee51c5a814261230636e6c54c90694f2 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Wed, 5 Jun 2024 12:01:41 -0400 Subject: [PATCH 005/350] update dashboard view --- src/components/map-view/component.jsx | 38 +++-- src/components/map-view/index.js | 25 ++-- src/components/map-view/selectors.js | 11 ++ ...nt.jsx => dashboard-sidebar-component.jsx} | 3 +- ...s => dashboard-sidebar-styles.module.scss} | 0 ...omponent.jsx => data-layers-component.jsx} | 0 .../dashboard-sidebar/data-layers/index.js | 2 +- .../sidebars/dashboard-sidebar/index.js | 2 +- .../dashboard-sidebar/species-info/index.js | 2 +- ...mponent.jsx => species-info-component.jsx} | 2 +- ...e.scss => species-info-styles.module.scss} | 0 .../dashboard-view-component.jsx | 62 ++++++++ .../dashboard-view/dashboard-view-config.js | 67 +++++++++ .../dashboard-view-selectors.js | 40 +++++ .../views/dashboard-view/dashboard-view.js | 43 ++++++ src/containers/views/dashboard/component.jsx | 19 --- src/containers/views/dashboard/index.js | 9 -- src/pages/dashboard/component.jsx | 20 --- src/pages/dashboard/dashboard-component.jsx | 62 ++++++++ src/pages/dashboard/dashboard-selectors.js | 138 ++++++++++++++++++ src/pages/dashboard/index.js | 26 +++- src/pages/dashboard/selectors.js | 35 ----- 22 files changed, 485 insertions(+), 121 deletions(-) rename src/containers/sidebars/dashboard-sidebar/{component.jsx => dashboard-sidebar-component.jsx} (89%) rename src/containers/sidebars/dashboard-sidebar/{styles.module.scss => dashboard-sidebar-styles.module.scss} (100%) rename src/containers/sidebars/dashboard-sidebar/data-layers/{component.jsx => data-layers-component.jsx} (100%) rename src/containers/sidebars/dashboard-sidebar/species-info/{component.jsx => species-info-component.jsx} (94%) rename src/containers/sidebars/dashboard-sidebar/species-info/{styles.module.scss => species-info-styles.module.scss} (100%) create mode 100644 src/containers/views/dashboard-view/dashboard-view-component.jsx create mode 100644 src/containers/views/dashboard-view/dashboard-view-config.js create mode 100644 src/containers/views/dashboard-view/dashboard-view-selectors.js create mode 100644 src/containers/views/dashboard-view/dashboard-view.js delete mode 100644 src/containers/views/dashboard/component.jsx delete mode 100644 src/containers/views/dashboard/index.js delete mode 100644 src/pages/dashboard/component.jsx create mode 100644 src/pages/dashboard/dashboard-component.jsx create mode 100644 src/pages/dashboard/dashboard-selectors.js delete mode 100644 src/pages/dashboard/selectors.js diff --git a/src/components/map-view/component.jsx b/src/components/map-view/component.jsx index 6e8079514..b820c631b 100644 --- a/src/components/map-view/component.jsx +++ b/src/components/map-view/component.jsx @@ -1,19 +1,31 @@ import React from 'react'; +import Spinner from 'components/spinner'; + +import styles from 'styles/themes/scene-theme.module.scss'; + export default function ViewComponent(props) { - const { map, view, mapName, mapId, children, loadState = 'loaded' } = props; - // if (loadState === 'loading') { - // return ( - // <> - //
- // - // - // ); - // } + const { + map, + view, + mapName, + mapId, + children, + loadState, + spinner = true, + } = props; + if (loadState === 'loading') { + return ( + <> +
+ + + ); + } if (loadState === 'loaded') { return (
{ console.error(err); @@ -133,7 +129,7 @@ function ViewContainer(props) { zoom: 6, center: [-3, 42], popup: null, - constraints: mapViewConstraints, + ...viewSettings, }); flatView.when(async () => { @@ -164,13 +160,14 @@ function ViewContainer(props) { useEffect(() => { if (map && view) { + setLoadState('loaded'); if (onViewLoad) { onViewLoad(map, view); } } }, [map, view]); - return ; + return ; } -export default ViewContainer; +export default connect(mapStateToProps, null)(ViewContainer); diff --git a/src/components/map-view/selectors.js b/src/components/map-view/selectors.js index e69de29bb..d6f72cff1 100644 --- a/src/components/map-view/selectors.js +++ b/src/components/map-view/selectors.js @@ -0,0 +1,11 @@ +import { createStructuredSelector } from 'reselect'; + +import { getIsGlobesMenuPages } from 'selectors/location-selectors'; + +const selectCenterOn = ({ location }) => + (location.query && location.query.centerOn) || null; + +export default createStructuredSelector({ + isGlobesMenuPages: getIsGlobesMenuPages, + centerOn: selectCenterOn, +}); diff --git a/src/containers/sidebars/dashboard-sidebar/component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx similarity index 89% rename from src/containers/sidebars/dashboard-sidebar/component.jsx rename to src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 42dd2cf26..6f0b73de5 100644 --- a/src/containers/sidebars/dashboard-sidebar/component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -1,7 +1,6 @@ import React from 'react'; -import styles from './styles.module.scss'; - +import styles from './dashboard-sidebar-styles.module.scss'; import DataLayerContainer from './data-layers'; import SpeciesInfoContainer from './species-info'; diff --git a/src/containers/sidebars/dashboard-sidebar/styles.module.scss b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss similarity index 100% rename from src/containers/sidebars/dashboard-sidebar/styles.module.scss rename to src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx similarity index 100% rename from src/containers/sidebars/dashboard-sidebar/data-layers/component.jsx rename to src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/index.js b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js index a714d68ac..e71e73498 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/index.js +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js @@ -1,6 +1,6 @@ import React from 'react'; -import DataLayerComponent from './component'; +import DataLayerComponent from './data-layers-component'; function DataLayerContainer(props) { return ; diff --git a/src/containers/sidebars/dashboard-sidebar/index.js b/src/containers/sidebars/dashboard-sidebar/index.js index 221f7cea5..96ea309bb 100644 --- a/src/containers/sidebars/dashboard-sidebar/index.js +++ b/src/containers/sidebars/dashboard-sidebar/index.js @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import Component from './component.jsx'; +import Component from './dashboard-sidebar-component.jsx'; import mapStateToProps from './selectors'; function DashboardSidebarContainer() { diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/index.js b/src/containers/sidebars/dashboard-sidebar/species-info/index.js index 2fbe9eeb4..827bf970d 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/index.js +++ b/src/containers/sidebars/dashboard-sidebar/species-info/index.js @@ -1,6 +1,6 @@ import React from 'react'; -import SpeciesInfoComponent from './component'; +import SpeciesInfoComponent from './species-info-component'; function SpeciesInfoContainer(props) { return ; diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/component.jsx b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx similarity index 94% rename from src/containers/sidebars/dashboard-sidebar/species-info/component.jsx rename to src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx index 2e06d8427..96b185278 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import styles from './styles.module.scss'; +import styles from './species-info-styles.module.scss'; function SpeciesInfoComponent() { return ( diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss similarity index 100% rename from src/containers/sidebars/dashboard-sidebar/species-info/styles.module.scss rename to src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx new file mode 100644 index 000000000..46c9e05b4 --- /dev/null +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -0,0 +1,62 @@ +import React from 'react'; + +import loadable from '@loadable/component'; + +import CountryLabelsLayer from 'containers/layers/country-labels-layer'; +import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; +import ArcgisLayerManager from 'containers/managers/arcgis-layer-manager'; +import SideMenu from 'containers/menus/sidemenu'; + +import MapView from '../../../components/map-view'; +import DashboardSidebar from '../../sidebars/dashboard-sidebar/dashboard-sidebar-component'; + +const LabelsLayer = loadable(() => import('containers/layers/labels-layer')); +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + +function DashboardViewComponent(props) { + const { + updatedActiveLayers, + onMapLoad, + sceneMode, + viewSettings, + countryISO, + countryName, + isFullscreenActive, + openedModal, + } = props; + + return ( + + + + + + + + + + + + + ); +} + +export default DashboardViewComponent; diff --git a/src/containers/views/dashboard-view/dashboard-view-config.js b/src/containers/views/dashboard-view/dashboard-view-config.js new file mode 100644 index 000000000..304f91434 --- /dev/null +++ b/src/containers/views/dashboard-view/dashboard-view-config.js @@ -0,0 +1,67 @@ +import { + GRAPHIC_LAYER, + ALL_TAXA_PRIORITY, + CITIES_LABELS_LAYER, + REGIONS_LABELS_LAYER, + ADMIN_AREAS_FEATURE_LAYER, + COUNTRIES_LABELS_FEATURE_LAYER, + LANDSCAPE_FEATURES_LABELS_LAYER, + FIREFLY_BASEMAP_LAYER, + SATELLITE_BASEMAP_LAYER, +} from 'constants/layers-slugs'; +import { + DEFAULT_OPACITY, + LAYERS_CATEGORIES, +} from 'constants/mol-layers-configs'; + +export default { + view: { + activeLayers: [ + { title: GRAPHIC_LAYER }, + { title: CITIES_LABELS_LAYER }, + { title: REGIONS_LABELS_LAYER, opacity: 0 }, + { title: COUNTRIES_LABELS_FEATURE_LAYER }, + { title: LANDSCAPE_FEATURES_LABELS_LAYER }, + { + title: ALL_TAXA_PRIORITY, + opacity: DEFAULT_OPACITY, + category: LAYERS_CATEGORIES.BIODIVERSITY, + }, + { title: ADMIN_AREAS_FEATURE_LAYER }, + ], + padding: { + left: 300, + }, + environment: { + atmosphereEnabled: false, + background: { + type: 'color', + color: [0, 10, 16], + }, + alphaCompositingEnabled: true, + }, + constraints: { + altitude: { + max: 35512548, + min: 10000, + }, + minZoom: 3, + rotationEnabled: false, + snapToZoom: false, + minScale: 147914381, + }, + ui: { + components: [], + }, + basemap: { + layersArray: [FIREFLY_BASEMAP_LAYER, SATELLITE_BASEMAP_LAYER], + }, + }, + ui: { + isSidebarOpen: false, + isFullscreenActive: false, + activeCategory: '', + sceneMode: 'data', + selectedAnalysisLayer: ADMIN_AREAS_FEATURE_LAYER, + }, +}; diff --git a/src/containers/views/dashboard-view/dashboard-view-selectors.js b/src/containers/views/dashboard-view/dashboard-view-selectors.js new file mode 100644 index 000000000..bae44a568 --- /dev/null +++ b/src/containers/views/dashboard-view/dashboard-view-selectors.js @@ -0,0 +1,40 @@ +import { createSelector, createStructuredSelector } from 'reselect'; + +import { selectAoiId } from 'selectors/aoi-selectors'; +import { selectUiUrlState } from 'selectors/location-selectors'; +import { selectTooltipData } from 'selectors/map-tooltip-selectors'; +import { selectSceneView } from 'selectors/scene-selectors'; +import { getSidebarTabActive } from 'selectors/ui-selectors'; + +import { + getSelectedAnalysisLayer, + getSelectedAnalysisTab, +} from 'pages/data-globe/data-globe-selectors'; + +import aoiSceneConfig from 'containers/scenes/aoi-scene/config'; + +const selectTemporaryPosition = ({ location }) => + (location.query && location.query.centerOn) || null; + +const getUiSettings = createSelector(selectUiUrlState, (uiUrlState) => { + return { + ...aoiSceneConfig.ui, + ...uiUrlState, + }; +}); + +const getActiveCategoryLayers = createSelector( + getUiSettings, + (uiSettings) => uiSettings.activeCategoryLayers +); + +export default createStructuredSelector({ + aoiId: selectAoiId, + activeCategoryLayers: getActiveCategoryLayers, + mapTooltipData: selectTooltipData, + sidebarTabActive: getSidebarTabActive, + selectedAnalysisLayer: getSelectedAnalysisLayer, + selectedAnalysisTab: getSelectedAnalysisTab, + centerOn: selectTemporaryPosition, + view: selectSceneView, +}); diff --git a/src/containers/views/dashboard-view/dashboard-view.js b/src/containers/views/dashboard-view/dashboard-view.js new file mode 100644 index 000000000..833cf5ef8 --- /dev/null +++ b/src/containers/views/dashboard-view/dashboard-view.js @@ -0,0 +1,43 @@ +import React, { useEffect, useState } from 'react'; +import { connect } from 'react-redux'; + +import unionBy from 'lodash/unionBy'; + +import { ADMIN_AREAS_FEATURE_LAYER } from 'constants/layers-slugs'; + +import Component from './dashboard-view-component'; +import mapStateToProps from './dashboard-view-selectors'; + +function DashboardView(props) { + const { activeLayers, changeUI, activeCategoryLayers, viewSettings } = props; + + const activeLayersWithoutAdmin = activeLayers.filter( + (ual) => ual.title !== ADMIN_AREAS_FEATURE_LAYER + ); + + const [updatedActiveLayers, setUpdatedActiveLayers] = useState( + activeLayersWithoutAdmin + ); + + useEffect(() => { + // Add temporary activeCategoryLayers to activeLayers at render and reset the param + if (activeCategoryLayers) { + setUpdatedActiveLayers( + unionBy(activeCategoryLayers, activeLayers, 'title') + ); + changeUI({ activeCategoryLayers: undefined }); + } else { + setUpdatedActiveLayers(activeLayers); + } + }, [activeLayers]); + + return ( + + ); +} + +export default connect(mapStateToProps, null)(DashboardView); diff --git a/src/containers/views/dashboard/component.jsx b/src/containers/views/dashboard/component.jsx deleted file mode 100644 index 5e5af8a19..000000000 --- a/src/containers/views/dashboard/component.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; - -import MapView from '../../../components/map-view'; -import DashboardSidebar from '../../sidebars/dashboard-sidebar/component'; - -const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; - -function DashboardViewComponent() { - return ( - - - - ); -} - -export default DashboardViewComponent; diff --git a/src/containers/views/dashboard/index.js b/src/containers/views/dashboard/index.js deleted file mode 100644 index ef0731491..000000000 --- a/src/containers/views/dashboard/index.js +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; - -import Component from './component'; - -function DashboardView(props) { - return ; -} - -export default DashboardView; diff --git a/src/pages/dashboard/component.jsx b/src/pages/dashboard/component.jsx deleted file mode 100644 index 9e002d34f..000000000 --- a/src/pages/dashboard/component.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React from 'react'; - -import cx from 'classnames'; - -import Logo from 'components/half-earth-logo'; - -import uiStyles from 'styles/ui.module.scss'; - -import DashboardView from '../../containers/views/dashboard'; - -function DashboardPageComponent(props) { - return ( - <> - - - - ); -} - -export default DashboardPageComponent; diff --git a/src/pages/dashboard/dashboard-component.jsx b/src/pages/dashboard/dashboard-component.jsx new file mode 100644 index 000000000..1e68b3211 --- /dev/null +++ b/src/pages/dashboard/dashboard-component.jsx @@ -0,0 +1,62 @@ +import React from 'react'; + +import cx from 'classnames'; + +import Logo from 'components/half-earth-logo'; + +import uiStyles from 'styles/ui.module.scss'; + +import DashboardView from '../../containers/views/dashboard-view/dashboard-view'; + +function DashboardComponent(props) { + const { + sceneMode, + countryISO, + countryName, + openedModal, + activeLayers, + handleMapLoad, + viewSettings, + isSidebarOpen, + activeCategory, + selectedSpecies, + isFullscreenActive, + handleGlobeUpdating, + countedActiveLayers, + isBiodiversityActive, + countryTooltipDisplayFor, + onboardingType, + onboardingStep, + waitingInteraction, + aoiId, + } = props; + return ( + <> + + handleMapLoad(map, activeLayers)} + {...props} + /> + + ); +} + +export default DashboardComponent; diff --git a/src/pages/dashboard/dashboard-selectors.js b/src/pages/dashboard/dashboard-selectors.js new file mode 100644 index 000000000..5a96498e6 --- /dev/null +++ b/src/pages/dashboard/dashboard-selectors.js @@ -0,0 +1,138 @@ +/* eslint-disable max-len */ +import { isEmpty } from 'lodash'; +import { createSelector, createStructuredSelector } from 'reselect'; + +import { getDataGlobeLayers } from 'selectors/layers-selectors'; +import { + selectGlobeUrlState, + selectUiUrlState, +} from 'selectors/location-selectors'; + +import dashboardViewConfig from '../../containers/views/dashboard-view/dashboard-view-config'; + +const selectBiodiversityData = ({ biodiversityData }) => + biodiversityData && (biodiversityData.data || null); +const selectMetadataData = ({ metadata }) => + metadata && (!isEmpty(metadata.data) || null); +const selectCountryExtent = ({ countryExtent }) => + countryExtent ? countryExtent.data : null; + +const getViewSettings = createSelector(selectGlobeUrlState, (globeUrlState) => { + return { + ...dashboardViewConfig.view, + ...globeUrlState, + }; +}); + +const getUiSettings = createSelector(selectUiUrlState, (uiUrlState) => { + return { + ...dashboardViewConfig.ui, + ...uiUrlState, + }; +}); + +export const getActiveLayers = createSelector( + getViewSettings, + (viewSettings) => viewSettings.activeLayers +); +export const getCountryTooltipDisplayFor = createSelector( + getViewSettings, + (viewSettings) => viewSettings.countryTooltipDisplayFor +); +const getGlobeUpdating = createSelector( + getViewSettings, + (viewSettings) => viewSettings.isGlobeUpdating +); +const getSelectedSpecies = createSelector( + getViewSettings, + (viewSettings) => viewSettings.selectedSpecies +); +export const getCountryISO = createSelector( + getViewSettings, + (viewSettings) => viewSettings.countryISO +); +const getCountryName = createSelector( + getViewSettings, + (viewSettings) => viewSettings.countryName +); +const getSidebarVisibility = createSelector( + getUiSettings, + (uiSettings) => uiSettings.isSidebarOpen +); +const getFullscreenActive = createSelector( + getUiSettings, + (uiSettings) => uiSettings.isFullscreenActive +); +const getActiveCategory = createSelector( + getUiSettings, + (uiSettings) => uiSettings.activeCategory +); +const getHalfEarthModalOpen = createSelector( + getUiSettings, + (uiSettings) => uiSettings.openedModal +); +const getSceneMode = createSelector( + getUiSettings, + (uiSettings) => uiSettings.sceneMode +); +const getCountryChallengesSelectedKey = createSelector( + getUiSettings, + (uiSettings) => uiSettings.countryChallengesSelectedKey +); +export const getLocalSceneFilters = createSelector( + getUiSettings, + (uiSettings) => uiSettings.localSceneFilters +); +export const getCountryChallengesSelectedFilter = createSelector( + getUiSettings, + (uiSettings) => uiSettings.countryChallengesSelectedFilter +); +export const getOnboardingType = createSelector( + getUiSettings, + (uiSettings) => uiSettings.onboardingType +); +export const getOnboardingStep = createSelector( + getUiSettings, + (uiSettings) => uiSettings.onboardingStep +); +export const getOnWaitingInteraction = createSelector( + getUiSettings, + (uiSettings) => uiSettings.waitingInteraction +); +export const getAOIId = createSelector( + getUiSettings, + (uiSettings) => uiSettings.aoiId +); +export const getSelectedAnalysisLayer = createSelector( + getUiSettings, + (uiSettings) => uiSettings.selectedAnalysisLayer +); +export const getSelectedAnalysisTab = createSelector( + getUiSettings, + (uiSettings) => uiSettings.selectedAnalysisTab || 'click' +); + +export default createStructuredSelector({ + viewSettings: getViewSettings, + sceneLayers: getDataGlobeLayers, + activeLayers: getActiveLayers, + countryISO: getCountryISO, + countryName: getCountryName, + isSidebarOpen: getSidebarVisibility, + isGlobeUpdating: getGlobeUpdating, + isFullscreenActive: getFullscreenActive, + activeCategory: getActiveCategory, + speciesCategories: selectBiodiversityData, + hasMetadata: selectMetadataData, + selectedSpecies: getSelectedSpecies, + openedModal: getHalfEarthModalOpen, + sceneMode: getSceneMode, + countryTooltipDisplayFor: getCountryTooltipDisplayFor, + countryChallengesSelectedKey: getCountryChallengesSelectedKey, + countryExtent: selectCountryExtent, + localSceneFilters: getLocalSceneFilters, + onboardingType: getOnboardingType, + onboardingStep: getOnboardingStep, + waitingInteraction: getOnWaitingInteraction, + aoiId: getAOIId, +}); diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index 152bae747..8caeb623c 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -1,11 +1,27 @@ import React from 'react'; import { connect } from 'react-redux'; -import Component from './component'; -import mapStateToProps from './selectors'; +import { activateLayersOnLoad } from 'utils/layer-manager-utils'; -function DashboardComponent(props) { - return ; +import { layersConfig } from 'constants/mol-layers-configs'; + +import { setBasemap } from '../../utils/layer-manager-utils.js'; + +import DashboardComponent from './dashboard-component'; +import mapStateToProps from './dashboard-selectors'; + +function DashboardContainer(props) { + const { viewSettings } = props; + const handleMapLoad = (map, activeLayers) => { + console.log('map view loaded', map); + setBasemap({ + map, + layersArray: viewSettings.basemap.layersArray, + }); + activateLayersOnLoad(map, activeLayers, layersConfig); + }; + + return ; } -export default connect(mapStateToProps, null)(DashboardComponent); +export default connect(mapStateToProps, null)(DashboardContainer); diff --git a/src/pages/dashboard/selectors.js b/src/pages/dashboard/selectors.js deleted file mode 100644 index e6865f665..000000000 --- a/src/pages/dashboard/selectors.js +++ /dev/null @@ -1,35 +0,0 @@ -import { createSelector, createStructuredSelector } from 'reselect'; - -const selectCountryIso = ({ location }) => location.payload.iso.toUpperCase(); -const selectCountriesData = ({ countryData }) => - countryData && countryData.data; - -const getCountryData = createSelector( - [selectCountriesData, selectCountryIso], - (countriesData, countryISO) => { - if (!countriesData || !countryISO) { - return null; - } - return countriesData[countryISO]; - } -); - -const getCountryName = createSelector([getCountryData], (countryData) => { - if (!countryData) { - return null; - } - return countryData.NAME_0; -}); - -const getCountryId = createSelector([getCountryData], (countryData) => { - if (!countryData) { - return null; - } - return countryData.OBJECTID; -}); - -export default createStructuredSelector({ - countryISO: selectCountryIso, - countryId: getCountryId, - countryName: getCountryName, -}); From 72bcf9952528c43f279fe175f425eb107aec6fc2 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 6 Jun 2024 09:01:36 -0400 Subject: [PATCH 006/350] adding data layers ui --- .../dashboard-sidebar-component.jsx | 2 +- .../dashboard-sidebar-styles.module.scss | 21 ++----------- .../data-layers/data-layers-component.jsx | 30 +++++++++++++++++-- .../data-layers-styles.module.scss | 9 ++++++ .../species-info-styles.module.scss | 19 +++++++----- .../dashboard-view/dashboard-view-config.js | 10 ------- 6 files changed, 53 insertions(+), 38 deletions(-) create mode 100644 src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 6f0b73de5..684d218e3 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -6,7 +6,7 @@ import SpeciesInfoContainer from './species-info'; function DashboardSidebar() { return ( -
+
diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss index 76ae53ffe..cc7d22e6f 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss @@ -3,34 +3,20 @@ @import 'styles/typography-extends'; @import 'styles/common-animations.module'; -$sidebar-content-top: 180px; -.sidebarContainer { - @include animationFunction($propertyToAnimate: all); - position: absolute; - height: calc(100vh - #{$nav-bar-height}); - width: calc(#{$sidebar-width} + 30px); - top: $nav-bar-height; - left: $site-gutter; - padding-bottom: $site-gutter; - padding-left: 5px; - - display: flex; - flex-direction: column; - gap: 10px; -} +$top: calc(#{$sidebar-top-margin} + #{$he-project-logo-size}); .container { @extend %verticalScrollbar; @include backdropBlur(); position: absolute; - top: $sidebar-content-top; + top: $top; left: $site-gutter; display: flex; flex-direction: column; border: $sidebar-border; border-radius: $sidebar-border-radius; - height: calc(100vh - #{$sidebar-content-top}); + height: calc(100vh - #{$top}); width: $sidebar-width; padding: $site-gutter; z-index: $bring-to-front; @@ -39,7 +25,6 @@ $sidebar-content-top: 180px; .sidenav{ display: flex; height: 100%; - background: rgba(255, 255, 255, 0.4); .icons{ display: flex; diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 2ce39b4f3..e86663f0b 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -1,7 +1,33 @@ import React from 'react'; -function DataLayerComponent() { - return
DataLayerComponent
; +import LayerToggle from 'components/layer-toggle'; + +import { FUTURE_PLACES_SLUG } from 'constants/analyze-areas-constants'; + +import styles from './data-layers-styles.module.scss'; + +function DataLayerComponent(props) { + const { map, activeLayers, handleLayerToggle, showProgress } = props; + const speciesLayers = []; + return ( +
+ + + {speciesLayers.map((layer) => ( + + ))} +
+ ); } export default DataLayerComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss new file mode 100644 index 000000000..23df7c001 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss @@ -0,0 +1,9 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.container{ + display: flex; + flex-direction: column; +} diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss index ce425595a..560465bb6 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss @@ -6,8 +6,6 @@ .species{ display: flex; flex-direction: column; - gap: 15px; - background-color: #efefef; .title{ display: flex; @@ -22,16 +20,20 @@ .info{ display: flex; flex-direction: column; - gap: 5px; + gap: 3px; + color: $white; + margin: 0 0 $site-gutter / 2 0; .commonName{ - font-weight: 700; + @extend %display1; font-size: 24px; + line-height: 1.5; } .taxa{ font-style: italic; font-size: 18px; + line-height: 1.5; } img{ @@ -39,9 +41,12 @@ height: 60px; } } + } - .description { - font-size: 14px; - } + .description { + @extend %bodyText; + color: $white; + margin: 0 0 $site-gutter / 2 0; + font-size: 14px; } } diff --git a/src/containers/views/dashboard-view/dashboard-view-config.js b/src/containers/views/dashboard-view/dashboard-view-config.js index 304f91434..d707ee476 100644 --- a/src/containers/views/dashboard-view/dashboard-view-config.js +++ b/src/containers/views/dashboard-view/dashboard-view-config.js @@ -1,6 +1,5 @@ import { GRAPHIC_LAYER, - ALL_TAXA_PRIORITY, CITIES_LABELS_LAYER, REGIONS_LABELS_LAYER, ADMIN_AREAS_FEATURE_LAYER, @@ -9,10 +8,6 @@ import { FIREFLY_BASEMAP_LAYER, SATELLITE_BASEMAP_LAYER, } from 'constants/layers-slugs'; -import { - DEFAULT_OPACITY, - LAYERS_CATEGORIES, -} from 'constants/mol-layers-configs'; export default { view: { @@ -22,11 +17,6 @@ export default { { title: REGIONS_LABELS_LAYER, opacity: 0 }, { title: COUNTRIES_LABELS_FEATURE_LAYER }, { title: LANDSCAPE_FEATURES_LABELS_LAYER }, - { - title: ALL_TAXA_PRIORITY, - opacity: DEFAULT_OPACITY, - category: LAYERS_CATEGORIES.BIODIVERSITY, - }, { title: ADMIN_AREAS_FEATURE_LAYER }, ], padding: { From f6df55fc87ca5f404709996f5b9e61c2734bb8ff Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 6 Jun 2024 14:30:53 -0400 Subject: [PATCH 007/350] add data layer checkboxes --- .../dashboard-sidebar-component.jsx | 5 +- .../data-layers/data-layers-component.jsx | 87 ++++++++++++++++++- .../data-layers-styles.module.scss | 21 +++++ .../dashboard-view-component.jsx | 2 +- 4 files changed, 108 insertions(+), 7 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 684d218e3..6d09677af 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -4,7 +4,8 @@ import styles from './dashboard-sidebar-styles.module.scss'; import DataLayerContainer from './data-layers'; import SpeciesInfoContainer from './species-info'; -function DashboardSidebar() { +function DashboardSidebar(props) { + const { activeLayers } = props; return (
@@ -15,7 +16,7 @@ function DashboardSidebar() { BI RA
- +
); diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index e86663f0b..b6822d722 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -1,6 +1,8 @@ import React from 'react'; +import Button from 'components/button'; import LayerToggle from 'components/layer-toggle'; +import SearchInput from 'components/search-input'; import { FUTURE_PLACES_SLUG } from 'constants/analyze-areas-constants'; @@ -8,12 +10,89 @@ import styles from './data-layers-styles.module.scss'; function DataLayerComponent(props) { const { map, activeLayers, handleLayerToggle, showProgress } = props; - const speciesLayers = []; + const speciesPublicLayers = [ + { + name: 'Point Observations', + value: 'PointObservations', + }, + { + name: 'Habitat Suitable Range', + value: 'PointObservations', + }, + { + name: 'Local Inventories', + value: 'PointObservations', + }, + { + name: 'Expert Range Maps', + value: 'PointObservations', + }, + { + name: 'Regional Checklists', + value: 'PointObservations', + }, + ]; + + const speciesPrivateLayers = [ + { + name: 'Point Observations', + value: 'PointObservations', + }, + ]; + + const speciesRegionsLayers = [ + { + name: 'Protected Areas', + value: 'PointObservations', + }, + { + name: 'Proposed Protected', + value: 'PointObservations', + }, + { + name: 'Administrative Layers', + value: 'PointObservations', + }, + ]; + return (
- - - {speciesLayers.map((layer) => ( + + +
- + {selectedIndex === 1 && ( + + )} + {selectedIndex === 2 && } + {selectedIndex === 3 && }
); diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss index cc7d22e6f..45d0c86ba 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-styles.module.scss @@ -18,7 +18,6 @@ $top: calc(#{$sidebar-top-margin} + #{$he-project-logo-size}); border-radius: $sidebar-border-radius; height: calc(100vh - #{$top}); width: $sidebar-width; - padding: $site-gutter; z-index: $bring-to-front; } @@ -32,10 +31,23 @@ $top: calc(#{$sidebar-top-margin} + #{$he-project-logo-size}); height: 100%; border-right: 1px solid; - span{ - display: inline-block; + button{ width: 50px; height: 50px; + + svg{ + width: 30px; + height: 30px; + } + + &.selected, + &:hover{ + background: $white; + + svg{ + fill: $black; + } + } } } } diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index b6822d722..eac34fa93 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -1,10 +1,20 @@ import React from 'react'; +import cx from 'classnames'; + import Button from 'components/button'; import LayerToggle from 'components/layer-toggle'; -import SearchInput from 'components/search-input'; +// import SearchInput from 'components/search-input'; + +import { + PROTECTION_SLUG, + LAND_HUMAN_PRESSURES_SLUG, + BIODIVERSITY_SLUG, +} from 'constants/analyze-areas-constants'; -import { FUTURE_PLACES_SLUG } from 'constants/analyze-areas-constants'; +import hrTheme from 'styles/themes/hr-theme.module.scss'; + +import { ReactComponent as ArrowIcon } from 'icons/arrow_right.svg'; import styles from './data-layers-styles.module.scss'; @@ -13,48 +23,50 @@ function DataLayerComponent(props) { const speciesPublicLayers = [ { name: 'Point Observations', - value: 'PointObservations', + value: 'countries_labels_layer', }, { name: 'Habitat Suitable Range', - value: 'PointObservations', + value: 'protected_areas_vector_tile_layer', }, { name: 'Local Inventories', - value: 'PointObservations', + value: 'regions_labels_layer', }, { name: 'Expert Range Maps', - value: 'PointObservations', + value: 'countries_data_layer', }, { name: 'Regional Checklists', - value: 'PointObservations', + value: 'community_areas_vector_tile_layer', }, ]; const speciesPrivateLayers = [ { name: 'Point Observations', - value: 'PointObservations', + value: 'PointObservations6', }, ]; const speciesRegionsLayers = [ { name: 'Protected Areas', - value: 'PointObservations', + value: 'PointObservations7', }, { name: 'Proposed Protected', - value: 'PointObservations', + value: 'PointObservations8', }, { name: 'Administrative Layers', - value: 'PointObservations', + value: 'PointObservations9', }, ]; + const isOpened = true; + return (
+ {speciesPublicLayers.map((layer) => ( ))} -

Distribute Data: Private

+
+ {speciesPrivateLayers.map((layer) => ( ))} -

Regions Data

+
+ {speciesRegionsLayers.map((layer) => ( ))}
diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss index 6f1a8ab9f..72f043f84 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss @@ -6,6 +6,8 @@ .container{ display: flex; flex-direction: column; + padding: 5px 10px; + width: 100%; .saveButton { color: $dark-text; @@ -24,7 +26,30 @@ max-width: 300px; } - h3{ + .sectionTitle{ + display: flex; + gap: 8px; + align-items: center; + font-size: 14px; + font-weight: 700; + text-transform: uppercase; + line-height: 1.5; color: $white; + + .arrowIcon { + fill: $white; + transform: rotate(90deg); + + &.isOpened { + transform:rotate(-90deg); + } + + transition: transform 0.2s ease; + + > path { + fill: inherit; + } } } + +} diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/index.js b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js index e71e73498..2ef6dd758 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/index.js +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/index.js @@ -1,9 +1,46 @@ -import React from 'react'; +import React, { useState } from 'react'; +import { connect } from 'react-redux'; +import metadataActions from 'redux_modules/metadata'; + +import * as urlActions from 'actions/url-actions'; + +import { layerManagerToggle } from 'utils/layer-manager-utils'; + +import { LAYERS_CATEGORIES } from 'constants/mol-layers-configs'; import DataLayerComponent from './data-layers-component'; +const actions = { ...metadataActions, ...urlActions }; + function DataLayerContainer(props) { - return ; + const { activeLayers, changeGlobe } = props; + + const [selectedLayers, setSelectedLayers] = useState([]); + + const handleLayerToggle = (option) => { + if (selectedLayers.find((layer) => layer === option.value)) { + setSelectedLayers( + selectedLayers.filter((layer) => layer !== option.value) + ); + } else { + setSelectedLayers([...selectedLayers, option.value]); + } + + layerManagerToggle( + option.value, + activeLayers, + changeGlobe, + LAYERS_CATEGORIES.PROTECTION + ); + }; + + return ( + + ); } -export default DataLayerContainer; +export default connect(null, actions)(DataLayerContainer); diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/index.js b/src/containers/sidebars/dashboard-sidebar/regions-analysis/index.js new file mode 100644 index 000000000..1b2acf3e3 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import RegionsAnalysisComponent from './regions-analysis-component'; + +function RegionsAnalysisContainer(props) { + return ; +} + +export default RegionsAnalysisContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx new file mode 100644 index 000000000..61b75c859 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx @@ -0,0 +1,9 @@ +import React from 'react'; + +import styles from './regions-analysis-styles.module.scss'; + +function RegionsAnalysisComponent() { + return
Regions Analysis
; +} + +export default RegionsAnalysisComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss new file mode 100644 index 000000000..eaddfa125 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss @@ -0,0 +1,12 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.container{ + display: flex; + flex-direction: column; + padding: 5px 10px; + width: 100%; + color: $white; +} diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss index 560465bb6..00810a4d2 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-styles.module.scss @@ -6,6 +6,7 @@ .species{ display: flex; flex-direction: column; + padding: $paragraph-gutter; .title{ display: flex; From 115d2a437dd75315c671af343706ef86ebaf7ee6 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 10 Jun 2024 14:30:08 -0400 Subject: [PATCH 009/350] add regions analysis draft --- .../regions-analysis-component.jsx | 44 ++++++++++++++++++- .../regions-analysis-styles.module.scss | 31 +++++++++++++ 2 files changed, 74 insertions(+), 1 deletion(-) diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx index 61b75c859..d470b3ab3 100644 --- a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx @@ -1,9 +1,51 @@ import React from 'react'; +import Button from 'components/button'; + +import hrTheme from 'styles/themes/hr-theme.module.scss'; + +import Checkbox from '../../../../components/checkbox/checkbox-component'; + import styles from './regions-analysis-styles.module.scss'; function RegionsAnalysisComponent() { - return
Regions Analysis
; + return ( +
+ Regions Analysis +
+

+ Select a region type below to explore a table of regions in which this + species is expected to occur. +

+
+ + + + + + +
+
+ +
+
+ ); } export default RegionsAnalysisComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss index eaddfa125..c91827085 100644 --- a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-styles.module.scss @@ -9,4 +9,35 @@ padding: 5px 10px; width: 100%; color: $white; + + .sectionTitle{ + font-size: 18px; + font-weight: 700; + text-transform: uppercase; + line-height: 1.5; + color: $white; + } + + p{ + font-size: 12px; + } + + .choices{ + display: flex; + flex-direction: column; + gap: 5px; + } + + .search{ + display: flex; + column-gap: 8px; + margin-top: 8px; + .saveButton { + color: $dark-text; + background-color: $brand-color-main; + &:hover { + background-color: $brand-color-main-hover; + } + } + } } From c4c61d47a0e38fd02ce2de25f363ef2f2ad15d6e Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 11 Jun 2024 11:06:51 -0400 Subject: [PATCH 010/350] add rangemap beta --- src/constants/layers-slugs.js | 2 ++ src/constants/layers-urls.js | 3 +++ src/constants/metadata.js | 2 ++ src/constants/mol-layers-configs.js | 8 ++++++++ .../data-layers/data-layers-component.jsx | 19 +++++++++++++------ 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/constants/layers-slugs.js b/src/constants/layers-slugs.js index 2a0b9784d..bb777cc67 100644 --- a/src/constants/layers-slugs.js +++ b/src/constants/layers-slugs.js @@ -212,3 +212,5 @@ export const REPTILES_LOOKUP = 'reptiles-lookup-table'; // NRC Landing Layers export const NRC_LANDING_LAYERS_SLUG = 'nrc-landing-layers'; export const EEZ_MARINE_AND_LAND_BORDERS = 'eez-marine-borders'; + +export const FOOBAR = 'foobar'; diff --git a/src/constants/layers-urls.js b/src/constants/layers-urls.js index adc324ae7..4efab16eb 100644 --- a/src/constants/layers-urls.js +++ b/src/constants/layers-urls.js @@ -122,6 +122,7 @@ import { MAMMALS_SACA_RICHNESS_TOTAL, MAMMALS_SACA_RARITY_TOTAL, BIRDS_SACA_RICHNESS_TOTAL, + FOOBAR, } from 'constants/layers-slugs'; const { REACT_APP_VERCEL_ENV } = process.env; @@ -156,6 +157,7 @@ const GADM_0_ADMIN_AREAS_FEATURE_LAYER_URL = const GADM_1_ADMIN_AREAS_FEATURE_LAYER_URL = 'https://utility.arcgis.com/usrsvcs/servers/340d03102060417c8a9f712754708216/rest/services/gadm1_precalculated_aoi_summaries_updated_20240321/FeatureServer'; +export const species = 'Accipiter_castanilius'; export const LAYERS_URLS = { [GLOBAL_SPI_FEATURE_LAYER]: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/SPI_Terrestrial_202403/FeatureServer', @@ -180,6 +182,7 @@ export const LAYERS_URLS = { 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/Educator_Ambassadors/FeatureServer', [COUNTRIES_LABELS_FEATURE_LAYER]: COUNTRIES_DATA_URL, [COUNTRIES_DATA_FEATURE_LAYER]: COUNTRIES_DATA_URL, + [FOOBAR]: `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/${species}_rangemap/FeatureServer`, [LANDSCAPE_FEATURES_LABELS_LAYER]: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/LandscapeUniqueRivers_gadm36/FeatureServer', [CITIES_LABELS_LAYER]: diff --git a/src/constants/metadata.js b/src/constants/metadata.js index 781044454..6e5e356be 100644 --- a/src/constants/metadata.js +++ b/src/constants/metadata.js @@ -70,6 +70,7 @@ import { CARBON_LAYER, MARINE_CARBON_LAYER, LAND_AND_MARINE_CARBON_LAYER, + FOOBAR, } from 'constants/layers-slugs'; export const SPECIES_PROTECTION_INDEX = 'spi-def'; @@ -158,4 +159,5 @@ export default { [MARINE_HUMAN_PRESSURES]: MARINE_HUMAN_PRESSURES, [HALF_EARTH_FUTURE_TILE_LAYER]: HALF_EARTH_FUTURE_METADATA_SLUG, [SPECIFIC_REGIONS_TILE_LAYER]: SPECIFIC_REGIONS_TILE_LAYER, + [FOOBAR]: FOOBAR, }; diff --git a/src/constants/mol-layers-configs.js b/src/constants/mol-layers-configs.js index 617310df6..a93875a7b 100644 --- a/src/constants/mol-layers-configs.js +++ b/src/constants/mol-layers-configs.js @@ -18,6 +18,7 @@ import { MARINE_CARBON_LAYER, PRIORITY_PLACES_POLYGONS, PROTECTED_AREAS_VECTOR_TILE_LAYER, + FOOBAR, HALF_EARTH_FUTURE_WDPA_LAYER, HALF_EARTH_FUTURE_TILE_LAYER, SPECIFIC_REGIONS_TILE_LAYER, @@ -317,6 +318,13 @@ export const layersConfig = { url: LAYERS_URLS[FEATURED_PLACES_LAYER], bbox: null, }, + [FOOBAR]: { + title: FOOBAR, + slug: FOOBAR, + type: LAYER_TYPES.FEATURE_LAYER, + url: LAYERS_URLS[FOOBAR], + bbox: null, + }, [PROTECTED_AREAS_VECTOR_TILE_LAYER]: { title: PROTECTED_AREAS_VECTOR_TILE_LAYER, slug: PROTECTED_AREAS_VECTOR_TILE_LAYER, diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index eac34fa93..7650f86b0 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -4,13 +4,20 @@ import cx from 'classnames'; import Button from 'components/button'; import LayerToggle from 'components/layer-toggle'; -// import SearchInput from 'components/search-input'; import { PROTECTION_SLUG, LAND_HUMAN_PRESSURES_SLUG, BIODIVERSITY_SLUG, } from 'constants/analyze-areas-constants'; +import { + COUNTRIES_LABELS_FEATURE_LAYER, + REGIONS_LABELS_LAYER, + COUNTRIES_DATA_FEATURE_LAYER, + PROTECTED_AREAS_VECTOR_TILE_LAYER, + FOOBAR, +} from 'constants/layers-slugs.js'; +// import SearchInput from 'components/search-input'; import hrTheme from 'styles/themes/hr-theme.module.scss'; @@ -23,23 +30,23 @@ function DataLayerComponent(props) { const speciesPublicLayers = [ { name: 'Point Observations', - value: 'countries_labels_layer', + value: COUNTRIES_LABELS_FEATURE_LAYER, }, { name: 'Habitat Suitable Range', - value: 'protected_areas_vector_tile_layer', + value: FOOBAR, }, { name: 'Local Inventories', - value: 'regions_labels_layer', + value: REGIONS_LABELS_LAYER, }, { name: 'Expert Range Maps', - value: 'countries_data_layer', + value: COUNTRIES_DATA_FEATURE_LAYER, }, { name: 'Regional Checklists', - value: 'community_areas_vector_tile_layer', + value: PROTECTED_AREAS_VECTOR_TILE_LAYER, }, ]; From cca12c333104ac0d6a68b9fc83fc7acbb35d80cb Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 11 Jun 2024 19:43:41 -0400 Subject: [PATCH 011/350] add layer on click for country and species --- src/components/map-view/index.js | 14 +++- src/constants/layers-urls.js | 4 +- .../biodiversity-indicators-component.jsx | 11 ++- ...biodiversity-indicators-styles.module.scss | 32 ++++++++ .../dashboard-sidebar-component.jsx | 8 +- .../data-layers/data-layers-component.jsx | 77 ++++++++++++++++--- .../data-layers-styles.module.scss | 38 +++++++-- .../regions-analysis-component.jsx | 16 +++- .../regions-analysis-styles.module.scss | 1 + .../dashboard-view-component.jsx | 9 ++- 10 files changed, 179 insertions(+), 31 deletions(-) diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js index 2119f607d..e148308c8 100644 --- a/src/components/map-view/index.js +++ b/src/components/map-view/index.js @@ -11,9 +11,17 @@ import mapStateToProps from './selectors'; const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; function ViewContainer(props) { - const { mapId, mapName, onMapLoad, onViewLoad, viewSettings } = props; + const { + mapId, + mapName, + onMapLoad, + onViewLoad, + viewSettings, + coordinates, + map, + setMap, + } = props; - const [map, setMap] = useState(null); const [view, setView] = useState(null); const [loadState, setLoadState] = useState('loading'); const [countryLayer, setCountryLayer] = useState(null); @@ -127,7 +135,7 @@ function ViewContainer(props) { map, container: `map-container-${mapName || mapId}`, zoom: 6, - center: [-3, 42], + center: coordinates, popup: null, ...viewSettings, }); diff --git a/src/constants/layers-urls.js b/src/constants/layers-urls.js index 4efab16eb..83e6f9644 100644 --- a/src/constants/layers-urls.js +++ b/src/constants/layers-urls.js @@ -157,7 +157,6 @@ const GADM_0_ADMIN_AREAS_FEATURE_LAYER_URL = const GADM_1_ADMIN_AREAS_FEATURE_LAYER_URL = 'https://utility.arcgis.com/usrsvcs/servers/340d03102060417c8a9f712754708216/rest/services/gadm1_precalculated_aoi_summaries_updated_20240321/FeatureServer'; -export const species = 'Accipiter_castanilius'; export const LAYERS_URLS = { [GLOBAL_SPI_FEATURE_LAYER]: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/SPI_Terrestrial_202403/FeatureServer', @@ -182,7 +181,8 @@ export const LAYERS_URLS = { 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/Educator_Ambassadors/FeatureServer', [COUNTRIES_LABELS_FEATURE_LAYER]: COUNTRIES_DATA_URL, [COUNTRIES_DATA_FEATURE_LAYER]: COUNTRIES_DATA_URL, - [FOOBAR]: `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/${species}_rangemap/FeatureServer`, + [FOOBAR]: + 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/occurrence_202301_alltaxa_drc_test/FeatureServer/0/query?where=taxa%20=%20%27mammals%27%20AND%20scientificname%20=%20%27Syncerus%20caffer%27', [LANDSCAPE_FEATURES_LABELS_LAYER]: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/LandscapeUniqueRivers_gadm36/FeatureServer', [CITIES_LABELS_LAYER]: diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx index 409e6fc94..f5c5b6c26 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx @@ -1,10 +1,19 @@ import React from 'react'; +import hrTheme from 'styles/themes/hr-theme.module.scss'; + import styles from './biodiversity-indicators-styles.module.scss'; function BioDiversityComponent() { return ( -
Biodiversity Indicators
+
+ Biodiversity Indicators +
+

+ *The Species Habitat Score is calculated using the habitat suitable + range map and remote sensing layers. +

+
); } diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss index eaddfa125..bb775f0d3 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss @@ -9,4 +9,36 @@ padding: 5px 10px; width: 100%; color: $white; + + .sectionTitle{ + font-size: 18px; + font-weight: 700; + text-transform: uppercase; + line-height: 1.5; + color: $white; + } + + p{ + font-size: 12px; + } + + .choices{ + display: flex; + flex-direction: column; + gap: 5px; + } + + .search{ + display: flex; + column-gap: 8px; + margin-top: 8px; + + .saveButton { + color: $dark-text; + background-color: $brand-color-main; + &:hover { + background-color: $brand-color-main-hover; + } + } + } } diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 3446b82ae..90a8a89ba 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -13,7 +13,7 @@ import RegionsAnalysisComponent from './regions-analysis/regions-analysis-compon import SpeciesInfoContainer from './species-info'; function DashboardSidebar(props) { - const { activeLayers } = props; + const { activeLayers, map } = props; const [selectedIndex, setSelectedIndex] = useState(1); return ( @@ -51,10 +51,10 @@ function DashboardSidebar(props) {
{selectedIndex === 1 && ( - + )} - {selectedIndex === 2 && } - {selectedIndex === 3 && } + {selectedIndex === 2 && } + {selectedIndex === 3 && }
); diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 7650f86b0..3d637394c 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -4,6 +4,9 @@ import cx from 'classnames'; import Button from 'components/button'; import LayerToggle from 'components/layer-toggle'; +import SearchLocation from 'components/search-location'; + +import EsriFeatureService from 'services/esri-feature-service'; import { PROTECTION_SLUG, @@ -17,7 +20,7 @@ import { PROTECTED_AREAS_VECTOR_TILE_LAYER, FOOBAR, } from 'constants/layers-slugs.js'; -// import SearchInput from 'components/search-input'; +import { SEARCH_TYPES } from 'constants/search-location-constants'; import hrTheme from 'styles/themes/hr-theme.module.scss'; @@ -26,7 +29,14 @@ import { ReactComponent as ArrowIcon } from 'icons/arrow_right.svg'; import styles from './data-layers-styles.module.scss'; function DataLayerComponent(props) { - const { map, activeLayers, handleLayerToggle, showProgress } = props; + const { + map, + activeLayers, + handleLayerToggle, + showProgress, + view, + selectedOption, + } = props; const speciesPublicLayers = [ { name: 'Point Observations', @@ -74,16 +84,49 @@ function DataLayerComponent(props) { const isOpened = true; + const showLayer = () => { + const taxa = 'mammals'; + const scientificname = 'Syncerus caffer'; + + const url = + 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/occurrence_202301_alltaxa_drc_test/FeatureServer/0'; + + EsriFeatureService.getFeatures({ + url, + whereClause: `taxa = '${taxa}' AND scientificname = '${scientificname}'`, + returnGeometry: true, + }).then((features) => { + const { layer } = features[0]; + map.add(layer); + }); + }; + return (
-
+
+ + + {speciesPublicLayers.map((layer) => ( ))}
-
- +
{selectedIndex === 1 && ( - + )} {selectedIndex === 2 && } {selectedIndex === 3 && } diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 3d637394c..d8e609a28 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -13,13 +13,7 @@ import { LAND_HUMAN_PRESSURES_SLUG, BIODIVERSITY_SLUG, } from 'constants/analyze-areas-constants'; -import { - COUNTRIES_LABELS_FEATURE_LAYER, - REGIONS_LABELS_LAYER, - COUNTRIES_DATA_FEATURE_LAYER, - PROTECTED_AREAS_VECTOR_TILE_LAYER, - FOOBAR, -} from 'constants/layers-slugs.js'; +import { PROTECTED_AREAS_VECTOR_TILE_LAYER } from 'constants/layers-slugs.js'; import { SEARCH_TYPES } from 'constants/search-location-constants'; import hrTheme from 'styles/themes/hr-theme.module.scss'; @@ -40,19 +34,19 @@ function DataLayerComponent(props) { const speciesPublicLayers = [ { name: 'Point Observations', - value: COUNTRIES_LABELS_FEATURE_LAYER, + value: 'PointObservations1', }, { name: 'Habitat Suitable Range', - value: FOOBAR, + value: 'PointObservations2', }, { name: 'Local Inventories', - value: REGIONS_LABELS_LAYER, + value: 'PointObservations3', }, { name: 'Expert Range Maps', - value: COUNTRIES_DATA_FEATURE_LAYER, + value: 'PointObservations4', }, { name: 'Regional Checklists', @@ -96,8 +90,9 @@ function DataLayerComponent(props) { whereClause: `taxa = '${taxa}' AND scientificname = '${scientificname}'`, returnGeometry: true, }).then((features) => { - const { layer } = features[0]; + const { layer, geometry } = features[0]; map.add(layer); + view.center = [geometry.longitude, geometry.latitude]; }); }; diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index eeedfa895..0d8cfcfc8 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import loadable from '@loadable/component'; @@ -7,15 +7,18 @@ import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; import ArcgisLayerManager from 'containers/managers/arcgis-layer-manager'; import SideMenu from 'containers/menus/sidemenu'; +import EsriFeatureService from 'services/esri-feature-service'; + +import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; + import MapView from '../../../components/map-view'; import DashboardSidebar from '../../sidebars/dashboard-sidebar/dashboard-sidebar-component'; const LabelsLayer = loadable(() => import('containers/layers/labels-layer')); -const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; function DashboardViewComponent(props) { const { - updatedActiveLayers, + activeLayers, onMapLoad, sceneMode, viewSettings, @@ -26,40 +29,53 @@ function DashboardViewComponent(props) { } = props; const [map, setMap] = useState(null); + const [view, setView] = useState(null); + + useEffect(() => { + EsriFeatureService.getFeatures({ + url: COUNTRIES_DATA_SERVICE_URL, + whereClause: `GID_0 = '${countryISO}'`, + returnGeometry: true, + }).then( + (features) => { + const { geometry } = features[0]; + if (geometry) { + view.center = [geometry.longitude, geometry.latitude]; + } + }, + [view, countryISO] + ); + }); return ( - + - + - + - + ); } diff --git a/src/containers/views/dashboard-view/dashboard-view-selectors.js b/src/containers/views/dashboard-view/dashboard-view-selectors.js deleted file mode 100644 index bae44a568..000000000 --- a/src/containers/views/dashboard-view/dashboard-view-selectors.js +++ /dev/null @@ -1,40 +0,0 @@ -import { createSelector, createStructuredSelector } from 'reselect'; - -import { selectAoiId } from 'selectors/aoi-selectors'; -import { selectUiUrlState } from 'selectors/location-selectors'; -import { selectTooltipData } from 'selectors/map-tooltip-selectors'; -import { selectSceneView } from 'selectors/scene-selectors'; -import { getSidebarTabActive } from 'selectors/ui-selectors'; - -import { - getSelectedAnalysisLayer, - getSelectedAnalysisTab, -} from 'pages/data-globe/data-globe-selectors'; - -import aoiSceneConfig from 'containers/scenes/aoi-scene/config'; - -const selectTemporaryPosition = ({ location }) => - (location.query && location.query.centerOn) || null; - -const getUiSettings = createSelector(selectUiUrlState, (uiUrlState) => { - return { - ...aoiSceneConfig.ui, - ...uiUrlState, - }; -}); - -const getActiveCategoryLayers = createSelector( - getUiSettings, - (uiSettings) => uiSettings.activeCategoryLayers -); - -export default createStructuredSelector({ - aoiId: selectAoiId, - activeCategoryLayers: getActiveCategoryLayers, - mapTooltipData: selectTooltipData, - sidebarTabActive: getSidebarTabActive, - selectedAnalysisLayer: getSelectedAnalysisLayer, - selectedAnalysisTab: getSelectedAnalysisTab, - centerOn: selectTemporaryPosition, - view: selectSceneView, -}); diff --git a/src/containers/views/dashboard-view/dashboard-view.js b/src/containers/views/dashboard-view/dashboard-view.js index 833cf5ef8..ab76fa052 100644 --- a/src/containers/views/dashboard-view/dashboard-view.js +++ b/src/containers/views/dashboard-view/dashboard-view.js @@ -1,43 +1,17 @@ -import React, { useEffect, useState } from 'react'; -import { connect } from 'react-redux'; - -import unionBy from 'lodash/unionBy'; - -import { ADMIN_AREAS_FEATURE_LAYER } from 'constants/layers-slugs'; +import React from 'react'; import Component from './dashboard-view-component'; -import mapStateToProps from './dashboard-view-selectors'; function DashboardView(props) { - const { activeLayers, changeUI, activeCategoryLayers, viewSettings } = props; - - const activeLayersWithoutAdmin = activeLayers.filter( - (ual) => ual.title !== ADMIN_AREAS_FEATURE_LAYER - ); - - const [updatedActiveLayers, setUpdatedActiveLayers] = useState( - activeLayersWithoutAdmin - ); - - useEffect(() => { - // Add temporary activeCategoryLayers to activeLayers at render and reset the param - if (activeCategoryLayers) { - setUpdatedActiveLayers( - unionBy(activeCategoryLayers, activeLayers, 'title') - ); - changeUI({ activeCategoryLayers: undefined }); - } else { - setUpdatedActiveLayers(activeLayers); - } - }, [activeLayers]); + const { activeLayers, viewSettings } = props; return ( ); } -export default connect(mapStateToProps, null)(DashboardView); +export default DashboardView; diff --git a/src/pages/dashboard/dashboard-component.jsx b/src/pages/dashboard/dashboard-component.jsx index 1e68b3211..27328c365 100644 --- a/src/pages/dashboard/dashboard-component.jsx +++ b/src/pages/dashboard/dashboard-component.jsx @@ -10,48 +10,26 @@ import DashboardView from '../../containers/views/dashboard-view/dashboard-view' function DashboardComponent(props) { const { - sceneMode, countryISO, countryName, - openedModal, activeLayers, handleMapLoad, viewSettings, isSidebarOpen, - activeCategory, selectedSpecies, - isFullscreenActive, - handleGlobeUpdating, - countedActiveLayers, isBiodiversityActive, - countryTooltipDisplayFor, - onboardingType, - onboardingStep, - waitingInteraction, - aoiId, } = props; return ( <> handleMapLoad(map, activeLayers)} {...props} /> diff --git a/src/pages/dashboard/dashboard-selectors.js b/src/pages/dashboard/dashboard-selectors.js index 5a96498e6..871bae428 100644 --- a/src/pages/dashboard/dashboard-selectors.js +++ b/src/pages/dashboard/dashboard-selectors.js @@ -10,12 +10,12 @@ import { import dashboardViewConfig from '../../containers/views/dashboard-view/dashboard-view-config'; +const selectCountryIso = ({ location }) => location.payload.iso.toUpperCase(); + const selectBiodiversityData = ({ biodiversityData }) => biodiversityData && (biodiversityData.data || null); const selectMetadataData = ({ metadata }) => metadata && (!isEmpty(metadata.data) || null); -const selectCountryExtent = ({ countryExtent }) => - countryExtent ? countryExtent.data : null; const getViewSettings = createSelector(selectGlobeUrlState, (globeUrlState) => { return { @@ -35,21 +35,13 @@ export const getActiveLayers = createSelector( getViewSettings, (viewSettings) => viewSettings.activeLayers ); -export const getCountryTooltipDisplayFor = createSelector( - getViewSettings, - (viewSettings) => viewSettings.countryTooltipDisplayFor -); -const getGlobeUpdating = createSelector( - getViewSettings, - (viewSettings) => viewSettings.isGlobeUpdating -); const getSelectedSpecies = createSelector( getViewSettings, (viewSettings) => viewSettings.selectedSpecies ); export const getCountryISO = createSelector( - getViewSettings, - (viewSettings) => viewSettings.countryISO + selectCountryIso, + (countryISO) => countryISO ); const getCountryName = createSelector( getViewSettings, @@ -59,58 +51,6 @@ const getSidebarVisibility = createSelector( getUiSettings, (uiSettings) => uiSettings.isSidebarOpen ); -const getFullscreenActive = createSelector( - getUiSettings, - (uiSettings) => uiSettings.isFullscreenActive -); -const getActiveCategory = createSelector( - getUiSettings, - (uiSettings) => uiSettings.activeCategory -); -const getHalfEarthModalOpen = createSelector( - getUiSettings, - (uiSettings) => uiSettings.openedModal -); -const getSceneMode = createSelector( - getUiSettings, - (uiSettings) => uiSettings.sceneMode -); -const getCountryChallengesSelectedKey = createSelector( - getUiSettings, - (uiSettings) => uiSettings.countryChallengesSelectedKey -); -export const getLocalSceneFilters = createSelector( - getUiSettings, - (uiSettings) => uiSettings.localSceneFilters -); -export const getCountryChallengesSelectedFilter = createSelector( - getUiSettings, - (uiSettings) => uiSettings.countryChallengesSelectedFilter -); -export const getOnboardingType = createSelector( - getUiSettings, - (uiSettings) => uiSettings.onboardingType -); -export const getOnboardingStep = createSelector( - getUiSettings, - (uiSettings) => uiSettings.onboardingStep -); -export const getOnWaitingInteraction = createSelector( - getUiSettings, - (uiSettings) => uiSettings.waitingInteraction -); -export const getAOIId = createSelector( - getUiSettings, - (uiSettings) => uiSettings.aoiId -); -export const getSelectedAnalysisLayer = createSelector( - getUiSettings, - (uiSettings) => uiSettings.selectedAnalysisLayer -); -export const getSelectedAnalysisTab = createSelector( - getUiSettings, - (uiSettings) => uiSettings.selectedAnalysisTab || 'click' -); export default createStructuredSelector({ viewSettings: getViewSettings, @@ -119,20 +59,7 @@ export default createStructuredSelector({ countryISO: getCountryISO, countryName: getCountryName, isSidebarOpen: getSidebarVisibility, - isGlobeUpdating: getGlobeUpdating, - isFullscreenActive: getFullscreenActive, - activeCategory: getActiveCategory, speciesCategories: selectBiodiversityData, hasMetadata: selectMetadataData, selectedSpecies: getSelectedSpecies, - openedModal: getHalfEarthModalOpen, - sceneMode: getSceneMode, - countryTooltipDisplayFor: getCountryTooltipDisplayFor, - countryChallengesSelectedKey: getCountryChallengesSelectedKey, - countryExtent: selectCountryExtent, - localSceneFilters: getLocalSceneFilters, - onboardingType: getOnboardingType, - onboardingStep: getOnboardingStep, - waitingInteraction: getOnWaitingInteraction, - aoiId: getAOIId, }); diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index 8caeb623c..d0811a98e 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -13,7 +13,6 @@ import mapStateToProps from './dashboard-selectors'; function DashboardContainer(props) { const { viewSettings } = props; const handleMapLoad = (map, activeLayers) => { - console.log('map view loaded', map); setBasemap({ map, layersArray: viewSettings.basemap.layersArray, From 7c3ff3c32cb46f7958363261939ce0bdb345639f Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Wed, 12 Jun 2024 11:22:54 -0400 Subject: [PATCH 013/350] highlight navigate to ISO --- src/components/map-view/index.js | 19 ++++++++------- .../dashboard-view-component.jsx | 24 +++++++++---------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js index 7226160fd..08b34deaf 100644 --- a/src/components/map-view/index.js +++ b/src/components/map-view/index.js @@ -21,6 +21,7 @@ function ViewContainer(props) { setMap, view, setView, + geo, } = props; // const [view, setView] = useState(null); @@ -140,15 +141,6 @@ function ViewContainer(props) { ...viewSettings, }); - flatView.when(async () => { - const query = { - geometry: flatView.center, - returnGeometry: true, - outFields: ['*'], - }; - await highlightCountry(query, flatView.center, flatView); - }); - flatView.on('click', async (event) => { const query = { geometry: flatView.toMap(event), @@ -175,6 +167,15 @@ function ViewContainer(props) { } }, [map, view]); + useEffect(() => { + const query = { + geometry: geo, + returnGeometry: true, + outFields: ['*'], + }; + highlightCountry(query, query.geometry, view); + }, [view, geo]); + return ; } diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index 0d8cfcfc8..93d401467 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -4,7 +4,6 @@ import loadable from '@loadable/component'; import CountryLabelsLayer from 'containers/layers/country-labels-layer'; import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; -import ArcgisLayerManager from 'containers/managers/arcgis-layer-manager'; import SideMenu from 'containers/menus/sidemenu'; import EsriFeatureService from 'services/esri-feature-service'; @@ -30,22 +29,22 @@ function DashboardViewComponent(props) { const [map, setMap] = useState(null); const [view, setView] = useState(null); + const [geo, setGeo] = useState(null); useEffect(() => { EsriFeatureService.getFeatures({ url: COUNTRIES_DATA_SERVICE_URL, whereClause: `GID_0 = '${countryISO}'`, returnGeometry: true, - }).then( - (features) => { - const { geometry } = features[0]; - if (geometry) { - view.center = [geometry.longitude, geometry.latitude]; - } - }, - [view, countryISO] - ); - }); + }).then((features) => { + const { geometry } = features[0]; + + if (geometry && view) { + view.center = [geometry.longitude, geometry.latitude]; + setGeo(geometry); + } + }); + }, [view, countryISO]); return ( - - Date: Wed, 12 Jun 2024 11:45:02 -0400 Subject: [PATCH 014/350] display points on map --- .../dashboard-sidebar/data-layers/data-layers-component.jsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index d8e609a28..0b4cac660 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -90,9 +90,8 @@ function DataLayerComponent(props) { whereClause: `taxa = '${taxa}' AND scientificname = '${scientificname}'`, returnGeometry: true, }).then((features) => { - const { layer, geometry } = features[0]; + const { layer } = features[0]; map.add(layer); - view.center = [geometry.longitude, geometry.latitude]; }); }; From 29c75b623346d55fb0fe749913abbca4728a7f53 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 17 Jun 2024 10:54:23 -0400 Subject: [PATCH 015/350] update mapviews --- src/components/map-view/index.js | 43 ++++++++----------- src/constants/layers-slugs.js | 2 - src/constants/layers-urls.js | 3 -- src/constants/metadata.js | 2 - src/constants/mol-layers-configs.js | 8 ---- .../data-layers/data-layers-component.jsx | 30 +++++++++++-- .../data-layers-styles.module.scss | 2 +- .../dashboard-view-component.jsx | 6 +++ 8 files changed, 52 insertions(+), 44 deletions(-) diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js index 08b34deaf..640f58857 100644 --- a/src/components/map-view/index.js +++ b/src/components/map-view/index.js @@ -8,15 +8,13 @@ import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs'; import Component from './component'; import mapStateToProps from './selectors'; -const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; - function ViewContainer(props) { const { onMapLoad, - onViewLoad, mapName, mapId, viewSettings, + loaderOptions, map, setMap, view, @@ -24,16 +22,11 @@ function ViewContainer(props) { geo, } = props; - // const [view, setView] = useState(null); const [loadState, setLoadState] = useState('loading'); const [countryLayer, setCountryLayer] = useState(null); const [graphicsLayer, setGraphicsLayer] = useState(null); const [groupLayer, setGroupLayer] = useState(null); - const loaderOptions = { - url: `https://js.arcgis.com/${API_VERSION}`, - }; - const highlightCountry = async (query, zoomGeometry, flatView) => { // country symbol - when user clicks on a country // we will query the country from the countries featurelayer @@ -120,6 +113,7 @@ function ViewContainer(props) { }); setMap(flatMap); + if (onMapLoad) { onMapLoad(flatMap); } @@ -141,14 +135,14 @@ function ViewContainer(props) { ...viewSettings, }); - flatView.on('click', async (event) => { - const query = { - geometry: flatView.toMap(event), - returnGeometry: true, - outFields: ['*'], - }; - await highlightCountry(query, query.geometry, flatView); - }); + // flatView.on('click', async (event) => { + // // const query = { + // // geometry: flatView.toMap(event), + // // returnGeometry: true, + // // outFields: ['*'], + // // }; + // // await highlightCountry(query, query.geometry, flatView); + // }); setView(flatView); }) @@ -161,19 +155,18 @@ function ViewContainer(props) { useEffect(() => { if (map && view) { setLoadState('loaded'); - if (onViewLoad) { - onViewLoad(map, view); - } } }, [map, view]); useEffect(() => { - const query = { - geometry: geo, - returnGeometry: true, - outFields: ['*'], - }; - highlightCountry(query, query.geometry, view); + if (view && geo) { + const query = { + geometry: geo, + returnGeometry: true, + outFields: ['*'], + }; + highlightCountry(query, query.geometry, view); + } }, [view, geo]); return ; diff --git a/src/constants/layers-slugs.js b/src/constants/layers-slugs.js index bb777cc67..2a0b9784d 100644 --- a/src/constants/layers-slugs.js +++ b/src/constants/layers-slugs.js @@ -212,5 +212,3 @@ export const REPTILES_LOOKUP = 'reptiles-lookup-table'; // NRC Landing Layers export const NRC_LANDING_LAYERS_SLUG = 'nrc-landing-layers'; export const EEZ_MARINE_AND_LAND_BORDERS = 'eez-marine-borders'; - -export const FOOBAR = 'foobar'; diff --git a/src/constants/layers-urls.js b/src/constants/layers-urls.js index 83e6f9644..adc324ae7 100644 --- a/src/constants/layers-urls.js +++ b/src/constants/layers-urls.js @@ -122,7 +122,6 @@ import { MAMMALS_SACA_RICHNESS_TOTAL, MAMMALS_SACA_RARITY_TOTAL, BIRDS_SACA_RICHNESS_TOTAL, - FOOBAR, } from 'constants/layers-slugs'; const { REACT_APP_VERCEL_ENV } = process.env; @@ -181,8 +180,6 @@ export const LAYERS_URLS = { 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/Educator_Ambassadors/FeatureServer', [COUNTRIES_LABELS_FEATURE_LAYER]: COUNTRIES_DATA_URL, [COUNTRIES_DATA_FEATURE_LAYER]: COUNTRIES_DATA_URL, - [FOOBAR]: - 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/occurrence_202301_alltaxa_drc_test/FeatureServer/0/query?where=taxa%20=%20%27mammals%27%20AND%20scientificname%20=%20%27Syncerus%20caffer%27', [LANDSCAPE_FEATURES_LABELS_LAYER]: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/LandscapeUniqueRivers_gadm36/FeatureServer', [CITIES_LABELS_LAYER]: diff --git a/src/constants/metadata.js b/src/constants/metadata.js index 6e5e356be..781044454 100644 --- a/src/constants/metadata.js +++ b/src/constants/metadata.js @@ -70,7 +70,6 @@ import { CARBON_LAYER, MARINE_CARBON_LAYER, LAND_AND_MARINE_CARBON_LAYER, - FOOBAR, } from 'constants/layers-slugs'; export const SPECIES_PROTECTION_INDEX = 'spi-def'; @@ -159,5 +158,4 @@ export default { [MARINE_HUMAN_PRESSURES]: MARINE_HUMAN_PRESSURES, [HALF_EARTH_FUTURE_TILE_LAYER]: HALF_EARTH_FUTURE_METADATA_SLUG, [SPECIFIC_REGIONS_TILE_LAYER]: SPECIFIC_REGIONS_TILE_LAYER, - [FOOBAR]: FOOBAR, }; diff --git a/src/constants/mol-layers-configs.js b/src/constants/mol-layers-configs.js index a93875a7b..617310df6 100644 --- a/src/constants/mol-layers-configs.js +++ b/src/constants/mol-layers-configs.js @@ -18,7 +18,6 @@ import { MARINE_CARBON_LAYER, PRIORITY_PLACES_POLYGONS, PROTECTED_AREAS_VECTOR_TILE_LAYER, - FOOBAR, HALF_EARTH_FUTURE_WDPA_LAYER, HALF_EARTH_FUTURE_TILE_LAYER, SPECIFIC_REGIONS_TILE_LAYER, @@ -318,13 +317,6 @@ export const layersConfig = { url: LAYERS_URLS[FEATURED_PLACES_LAYER], bbox: null, }, - [FOOBAR]: { - title: FOOBAR, - slug: FOOBAR, - type: LAYER_TYPES.FEATURE_LAYER, - url: LAYERS_URLS[FOOBAR], - bbox: null, - }, [PROTECTED_AREAS_VECTOR_TILE_LAYER]: { title: PROTECTED_AREAS_VECTOR_TILE_LAYER, slug: PROTECTED_AREAS_VECTOR_TILE_LAYER, diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 0b4cac660..f53b8bdea 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -16,10 +16,13 @@ import { import { PROTECTED_AREAS_VECTOR_TILE_LAYER } from 'constants/layers-slugs.js'; import { SEARCH_TYPES } from 'constants/search-location-constants'; +// import theme from 'styles/themes/checkboxes-theme.module.scss'; import hrTheme from 'styles/themes/hr-theme.module.scss'; import { ReactComponent as ArrowIcon } from 'icons/arrow_right.svg'; +// import CheckboxType from '../../../../components/layer-toggle/checkbox-type'; + import styles from './data-layers-styles.module.scss'; function DataLayerComponent(props) { @@ -95,6 +98,8 @@ function DataLayerComponent(props) { }); }; + // const [isChecked, setIsChecked] = useState(false); + return (
Data Layers @@ -133,6 +138,26 @@ function DataLayerComponent(props) { Show Layer + {/* { + setIsChecked(!isChecked); + }} + /> */} + + {/* */} + {speciesPublicLayers.map((layer) => ( ))} @@ -169,7 +193,7 @@ function DataLayerComponent(props) { showProgress={showProgress} activeLayers={activeLayers} themeCategorySlug={LAND_HUMAN_PRESSURES_SLUG} - onChange={handleLayerToggle} + onChange={showLayer} /> ))}
diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss index d8e481ddc..72fe5aa2f 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-styles.module.scss @@ -76,6 +76,6 @@ fill: inherit; } } + } } -} diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index 93d401467..5627d5cb6 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -13,6 +13,8 @@ import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; import MapView from '../../../components/map-view'; import DashboardSidebar from '../../sidebars/dashboard-sidebar/dashboard-sidebar-component'; +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + const LabelsLayer = loadable(() => import('containers/layers/labels-layer')); function DashboardViewComponent(props) { @@ -56,6 +58,9 @@ function DashboardViewComponent(props) { view={view} setView={setView} geo={geo} + loaderOptions={{ + url: `https://js.arcgis.com/${API_VERSION}`, + }} > @@ -65,6 +70,7 @@ function DashboardViewComponent(props) { countryName={countryName} activeLayers={activeLayers} /> + Date: Tue, 18 Jun 2024 14:56:36 -0400 Subject: [PATCH 016/350] update layer toggle controls --- .../dashboard-sidebar-component.jsx | 3 + .../data-layers/data-layers-component.jsx | 144 +++++++++--------- src/pages/dashboard/dashboard-selectors.js | 2 - src/styles/settings.scss | 6 + .../themes/checkboxes-theme.module.scss | 39 +++++ 5 files changed, 120 insertions(+), 74 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index a2ad62aa6..260ea6471 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -24,6 +24,7 @@ function DashboardSidebar(props) {
- - - - {/* { - setIsChecked(!isChecked); - }} - /> */} - - {/* */} - - {speciesPublicLayers.map((layer) => ( + {speciesLayers.map((layer) => ( ))}
@@ -190,10 +190,10 @@ function DataLayerComponent(props) { type="checkbox" variant="light" key={layer.value} - showProgress={showProgress} + isChecked={layer.isChecked} activeLayers={activeLayers} - themeCategorySlug={LAND_HUMAN_PRESSURES_SLUG} - onChange={showLayer} + onChange={displayLayer} + themeCategorySlug={layer.value} /> ))}
@@ -216,10 +216,10 @@ function DataLayerComponent(props) { type="checkbox" variant="light" key={layer.value} - showProgress={showProgress} + isChecked={layer.isChecked} activeLayers={activeLayers} - onChange={handleLayerToggle} - themeCategorySlug={BIODIVERSITY_SLUG} + onChange={displayLayer} + themeCategorySlug={layer.value} /> ))}
diff --git a/src/pages/dashboard/dashboard-selectors.js b/src/pages/dashboard/dashboard-selectors.js index 871bae428..a323842db 100644 --- a/src/pages/dashboard/dashboard-selectors.js +++ b/src/pages/dashboard/dashboard-selectors.js @@ -2,7 +2,6 @@ import { isEmpty } from 'lodash'; import { createSelector, createStructuredSelector } from 'reselect'; -import { getDataGlobeLayers } from 'selectors/layers-selectors'; import { selectGlobeUrlState, selectUiUrlState, @@ -54,7 +53,6 @@ const getSidebarVisibility = createSelector( export default createStructuredSelector({ viewSettings: getViewSettings, - sceneLayers: getDataGlobeLayers, activeLayers: getActiveLayers, countryISO: getCountryISO, countryName: getCountryName, diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 677bb7863..8a5d6edce 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -110,6 +110,12 @@ $spi-chart-gradient: linear-gradient( ); $challenges-view-background: #040e14; $warning: #dc2626; +$pointObservations: #54B04A; +$habitatSuitableRange: #E7C750; +$localInventories: #7D4182; +$expertRangeMap: #5A9AB5; +$regionalChecklist: #AE305C; +$privatePointObservations: #E93C39; // country ranking $endemic-species: #f8d300; diff --git a/src/styles/themes/checkboxes-theme.module.scss b/src/styles/themes/checkboxes-theme.module.scss index 1b2ce6a54..f7613bf2e 100644 --- a/src/styles/themes/checkboxes-theme.module.scss +++ b/src/styles/themes/checkboxes-theme.module.scss @@ -75,3 +75,42 @@ } } + + + +.pointObservations{ + input:checked+label::after { + background-color: $pointObservations; + } +} + +.privatePointObservations{ + input:checked+label::after { + background-color: $privatePointObservations; + } +} + + +.habitatSuitableRange{ + input:checked+label::after { + background-color: $habitatSuitableRange; + } +} + +.localInventories{ + input:checked+label::after { + background-color: $localInventories; + } +} + +.expertRangeMap{ + input:checked+label::after { + background-color: $expertRangeMap; + } +} + +.regionalChecklist{ + input:checked+label::after { + background-color: $regionalChecklist + } +} From 4e768c0a683259dc27eb3b5197dfd747b2c00d6f Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 18 Jun 2024 16:48:15 -0400 Subject: [PATCH 017/350] add dashboard trends endpoint --- src/app.jsx | 5 ++ .../score-distributions/index.js | 9 ++ .../score-distributions-component.jsx | 35 ++++++++ .../score-distributions-styles.module.scss | 66 ++++++++++++++ .../temporal-trends/index.js | 9 ++ .../temporal-trends-component.jsx | 45 ++++++++++ .../temporal-trends-styles.module.scss | 66 ++++++++++++++ .../dashboard-trends-view-component.jsx | 90 +++++++++++++++++++ .../dashboard-trends-view-config.js | 57 ++++++++++++ .../dashboard-trends-view.js | 17 ++++ .../dashboard-view-component.jsx | 3 +- .../dashboard-trends-component.jsx | 40 +++++++++ .../dashboard-trends-selectors.js | 63 +++++++++++++ src/pages/dashboard-trends/index.js | 26 ++++++ src/router.ts | 7 +- 15 files changed, 536 insertions(+), 2 deletions(-) create mode 100644 src/containers/sidebars/dashboard-sidebar/score-distributions/index.js create mode 100644 src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx create mode 100644 src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss create mode 100644 src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js create mode 100644 src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx create mode 100644 src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss create mode 100644 src/containers/views/dashboard-trends-view/dashboard-trends-view-component.jsx create mode 100644 src/containers/views/dashboard-trends-view/dashboard-trends-view-config.js create mode 100644 src/containers/views/dashboard-trends-view/dashboard-trends-view.js create mode 100644 src/pages/dashboard-trends/dashboard-trends-component.jsx create mode 100644 src/pages/dashboard-trends/dashboard-trends-selectors.js create mode 100644 src/pages/dashboard-trends/index.js diff --git a/src/app.jsx b/src/app.jsx index bbabbff37..24298c2ef 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -32,6 +32,9 @@ const NationalReportCard = loadable(() => import('pages/nrc')); const NationalReportCardLanding = loadable(() => import('pages/nrc-landing')); const AreaOfInterest = loadable(() => import('pages/aoi')); const DashboardComponent = loadable(() => import('pages/dashboard')); +const DashboardTrendsComponent = loadable(() => + import('pages/dashboard-trends') +); const mapStateToProps = ({ location }) => ({ route: location.routesMap[location.type], @@ -65,6 +68,8 @@ function AppLayout(props) { return ; case 'dashboard': return ; + case 'dashboard-trends': + return ; default: return isMobile ? : ; } diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/index.js b/src/containers/sidebars/dashboard-sidebar/score-distributions/index.js new file mode 100644 index 000000000..4da31c401 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/score-distributions/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import ScoreDistributionsComponent from './score-distributions-component'; + +function ScoreDistributionsContainer(props) { + return ; +} + +export default ScoreDistributionsContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx new file mode 100644 index 000000000..105c11730 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx @@ -0,0 +1,35 @@ +import React from 'react'; + +import Button from 'components/button'; + +import styles from './score-distributions-styles.module.scss'; + +function ScoreDistributionsComponent() { + return ( +
+
+
+ Score Distributions +
+
+

+ View the distribution of the individual Species Protection Scores for + all terrestrial vertebrates. Amphibians have the lowest average + protection score while birds have the highest. +

+
+
+
+ ); +} + +export default ScoreDistributionsComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss new file mode 100644 index 000000000..17375b683 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss @@ -0,0 +1,66 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.temporalTrends{ + display: flex; + flex-direction: column; + padding: $paragraph-gutter; + + .title{ + display: flex; + gap: 10px; + + img{ + width: 130px; + height: 130px; + margin-top: 8px; + } + + .info{ + display: flex; + flex-direction: column; + gap: 3px; + color: $white; + margin: 0 0 $site-gutter / 2 0; + + .commonName{ + @extend %display1; + font-size: 24px; + line-height: 1.5; + } + } + } + + .description { + @extend %bodyText; + color: $white; + margin: 0 0 $site-gutter / 2 0; + font-size: 14px; + } + + .options{ + display: flex; + flex-direction: column; + row-gap: 8px; + margin-top: 10px; + + .saveButton { + color: $dark-text; + background-color: $brand-color-main; + &:hover { + background-color: $brand-color-main-hover; + } + } + + .helpText{ + color: #FFF; + font-family: "Open Sans"; + font-size: 9px; + font-style: italic; + font-weight: 400; + line-height: normal; + } + } +} diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js b/src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js new file mode 100644 index 000000000..d42b387fb --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import TemporalTrendsComponent from './temporal-trends-component'; + +function TemporalTrendsContainer(props) { + return ; +} + +export default TemporalTrendsContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx new file mode 100644 index 000000000..db071073b --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx @@ -0,0 +1,45 @@ +import React from 'react'; + +import Button from 'components/button'; + +import styles from './temporal-trends-styles.module.scss'; + +function TemporalTrendsComponent() { + return ( +
+
+
+ Temporal Trends +
+
+

+ Since 1980, the Democratic Republic of the Congo has added 328357 km2 of + land into its protected area network, representing 14% of the total land + in the country, increasing its Species Protection Index from 27.21 in + 1980 to 63 in 2023. +

+
+
+
+ ); +} + +export default TemporalTrendsComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss new file mode 100644 index 000000000..17375b683 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss @@ -0,0 +1,66 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.temporalTrends{ + display: flex; + flex-direction: column; + padding: $paragraph-gutter; + + .title{ + display: flex; + gap: 10px; + + img{ + width: 130px; + height: 130px; + margin-top: 8px; + } + + .info{ + display: flex; + flex-direction: column; + gap: 3px; + color: $white; + margin: 0 0 $site-gutter / 2 0; + + .commonName{ + @extend %display1; + font-size: 24px; + line-height: 1.5; + } + } + } + + .description { + @extend %bodyText; + color: $white; + margin: 0 0 $site-gutter / 2 0; + font-size: 14px; + } + + .options{ + display: flex; + flex-direction: column; + row-gap: 8px; + margin-top: 10px; + + .saveButton { + color: $dark-text; + background-color: $brand-color-main; + &:hover { + background-color: $brand-color-main-hover; + } + } + + .helpText{ + color: #FFF; + font-family: "Open Sans"; + font-size: 9px; + font-style: italic; + font-weight: 400; + line-height: normal; + } + } +} diff --git a/src/containers/views/dashboard-trends-view/dashboard-trends-view-component.jsx b/src/containers/views/dashboard-trends-view/dashboard-trends-view-component.jsx new file mode 100644 index 000000000..9570c0a63 --- /dev/null +++ b/src/containers/views/dashboard-trends-view/dashboard-trends-view-component.jsx @@ -0,0 +1,90 @@ +import React, { useEffect, useState } from 'react'; + +import loadable from '@loadable/component'; + +import CountryLabelsLayer from 'containers/layers/country-labels-layer'; +import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; +import SideMenu from 'containers/menus/sidemenu'; + +import MapView from 'components/map-view'; + +import EsriFeatureService from 'services/esri-feature-service'; + +import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; + +import ScoreDistributionsContainer from '../../sidebars/dashboard-sidebar/score-distributions'; +import TemporalTrendsContainer from '../../sidebars/dashboard-sidebar/temporal-trends'; + +const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; + +const LabelsLayer = loadable(() => import('containers/layers/labels-layer')); + +function DashboardTrendsViewComponent(props) { + const { + activeLayers, + onMapLoad, + sceneMode, + viewSettings, + countryISO, + countryName, + isFullscreenActive, + openedModal, + } = props; + + const [map, setMap] = useState(null); + const [view, setView] = useState(null); + const [geo, setGeo] = useState(null); + + useEffect(() => { + EsriFeatureService.getFeatures({ + url: COUNTRIES_DATA_SERVICE_URL, + whereClause: `GID_0 = '${countryISO}'`, + returnGeometry: true, + }).then((features) => { + const { geometry } = features[0]; + + if (geometry && view) { + view.center = [geometry.longitude, geometry.latitude]; + setGeo(geometry); + } + }); + }, [view, countryISO]); + + return ( + + + + + + + + + + + + + ); +} + +export default DashboardTrendsViewComponent; diff --git a/src/containers/views/dashboard-trends-view/dashboard-trends-view-config.js b/src/containers/views/dashboard-trends-view/dashboard-trends-view-config.js new file mode 100644 index 000000000..d707ee476 --- /dev/null +++ b/src/containers/views/dashboard-trends-view/dashboard-trends-view-config.js @@ -0,0 +1,57 @@ +import { + GRAPHIC_LAYER, + CITIES_LABELS_LAYER, + REGIONS_LABELS_LAYER, + ADMIN_AREAS_FEATURE_LAYER, + COUNTRIES_LABELS_FEATURE_LAYER, + LANDSCAPE_FEATURES_LABELS_LAYER, + FIREFLY_BASEMAP_LAYER, + SATELLITE_BASEMAP_LAYER, +} from 'constants/layers-slugs'; + +export default { + view: { + activeLayers: [ + { title: GRAPHIC_LAYER }, + { title: CITIES_LABELS_LAYER }, + { title: REGIONS_LABELS_LAYER, opacity: 0 }, + { title: COUNTRIES_LABELS_FEATURE_LAYER }, + { title: LANDSCAPE_FEATURES_LABELS_LAYER }, + { title: ADMIN_AREAS_FEATURE_LAYER }, + ], + padding: { + left: 300, + }, + environment: { + atmosphereEnabled: false, + background: { + type: 'color', + color: [0, 10, 16], + }, + alphaCompositingEnabled: true, + }, + constraints: { + altitude: { + max: 35512548, + min: 10000, + }, + minZoom: 3, + rotationEnabled: false, + snapToZoom: false, + minScale: 147914381, + }, + ui: { + components: [], + }, + basemap: { + layersArray: [FIREFLY_BASEMAP_LAYER, SATELLITE_BASEMAP_LAYER], + }, + }, + ui: { + isSidebarOpen: false, + isFullscreenActive: false, + activeCategory: '', + sceneMode: 'data', + selectedAnalysisLayer: ADMIN_AREAS_FEATURE_LAYER, + }, +}; diff --git a/src/containers/views/dashboard-trends-view/dashboard-trends-view.js b/src/containers/views/dashboard-trends-view/dashboard-trends-view.js new file mode 100644 index 000000000..ae2cb77ad --- /dev/null +++ b/src/containers/views/dashboard-trends-view/dashboard-trends-view.js @@ -0,0 +1,17 @@ +import React from 'react'; + +import Component from './dashboard-trends-view-component'; + +function DashboardTrendsView(props) { + const { activeLayers, viewSettings } = props; + + return ( + + ); +} + +export default DashboardTrendsView; diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index 5627d5cb6..69eb7671e 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -6,11 +6,12 @@ import CountryLabelsLayer from 'containers/layers/country-labels-layer'; import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; import SideMenu from 'containers/menus/sidemenu'; +import MapView from 'components/map-view'; + import EsriFeatureService from 'services/esri-feature-service'; import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; -import MapView from '../../../components/map-view'; import DashboardSidebar from '../../sidebars/dashboard-sidebar/dashboard-sidebar-component'; const { REACT_APP_ARGISJS_API_VERSION: API_VERSION } = process.env; diff --git a/src/pages/dashboard-trends/dashboard-trends-component.jsx b/src/pages/dashboard-trends/dashboard-trends-component.jsx new file mode 100644 index 000000000..056a80c2d --- /dev/null +++ b/src/pages/dashboard-trends/dashboard-trends-component.jsx @@ -0,0 +1,40 @@ +import React from 'react'; + +import cx from 'classnames'; + +import Logo from 'components/half-earth-logo'; + +import uiStyles from 'styles/ui.module.scss'; + +import DashboardTrendsView from '../../containers/views/dashboard-trends-view/dashboard-trends-view'; + +function DashboardTrendsComponent(props) { + const { + countryISO, + countryName, + activeLayers, + handleMapLoad, + viewSettings, + isSidebarOpen, + selectedSpecies, + isBiodiversityActive, + } = props; + return ( + <> + + handleMapLoad(map, activeLayers)} + {...props} + /> + + ); +} + +export default DashboardTrendsComponent; diff --git a/src/pages/dashboard-trends/dashboard-trends-selectors.js b/src/pages/dashboard-trends/dashboard-trends-selectors.js new file mode 100644 index 000000000..a323842db --- /dev/null +++ b/src/pages/dashboard-trends/dashboard-trends-selectors.js @@ -0,0 +1,63 @@ +/* eslint-disable max-len */ +import { isEmpty } from 'lodash'; +import { createSelector, createStructuredSelector } from 'reselect'; + +import { + selectGlobeUrlState, + selectUiUrlState, +} from 'selectors/location-selectors'; + +import dashboardViewConfig from '../../containers/views/dashboard-view/dashboard-view-config'; + +const selectCountryIso = ({ location }) => location.payload.iso.toUpperCase(); + +const selectBiodiversityData = ({ biodiversityData }) => + biodiversityData && (biodiversityData.data || null); +const selectMetadataData = ({ metadata }) => + metadata && (!isEmpty(metadata.data) || null); + +const getViewSettings = createSelector(selectGlobeUrlState, (globeUrlState) => { + return { + ...dashboardViewConfig.view, + ...globeUrlState, + }; +}); + +const getUiSettings = createSelector(selectUiUrlState, (uiUrlState) => { + return { + ...dashboardViewConfig.ui, + ...uiUrlState, + }; +}); + +export const getActiveLayers = createSelector( + getViewSettings, + (viewSettings) => viewSettings.activeLayers +); +const getSelectedSpecies = createSelector( + getViewSettings, + (viewSettings) => viewSettings.selectedSpecies +); +export const getCountryISO = createSelector( + selectCountryIso, + (countryISO) => countryISO +); +const getCountryName = createSelector( + getViewSettings, + (viewSettings) => viewSettings.countryName +); +const getSidebarVisibility = createSelector( + getUiSettings, + (uiSettings) => uiSettings.isSidebarOpen +); + +export default createStructuredSelector({ + viewSettings: getViewSettings, + activeLayers: getActiveLayers, + countryISO: getCountryISO, + countryName: getCountryName, + isSidebarOpen: getSidebarVisibility, + speciesCategories: selectBiodiversityData, + hasMetadata: selectMetadataData, + selectedSpecies: getSelectedSpecies, +}); diff --git a/src/pages/dashboard-trends/index.js b/src/pages/dashboard-trends/index.js new file mode 100644 index 000000000..7f70cea6b --- /dev/null +++ b/src/pages/dashboard-trends/index.js @@ -0,0 +1,26 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +import { activateLayersOnLoad } from 'utils/layer-manager-utils'; + +import { layersConfig } from 'constants/mol-layers-configs'; + +import { setBasemap } from '../../utils/layer-manager-utils.js'; + +import DashboardTrendsComponent from './dashboard-trends-component'; +import mapStateToProps from './dashboard-trends-selectors'; + +function DashboardTrendsContainer(props) { + const { viewSettings } = props; + const handleMapLoad = (map, activeLayers) => { + setBasemap({ + map, + layersArray: viewSettings.basemap.layersArray, + }); + activateLayersOnLoad(map, activeLayers, layersConfig); + }; + + return ; +} + +export default connect(mapStateToProps, null)(DashboardTrendsContainer); diff --git a/src/router.ts b/src/router.ts index 13fa460e5..c6c47b33f 100644 --- a/src/router.ts +++ b/src/router.ts @@ -1,6 +1,6 @@ +import { connectRoutes, NOT_FOUND, redirect } from 'redux-first-router'; import { decodeUrlForState, encodeStateForUrl } from 'utils/state-to-url'; -import { connectRoutes, NOT_FOUND, redirect } from 'redux-first-router'; import type { RoutesMap } from 'redux-first-router'; export const LANDING = 'location/'; @@ -12,6 +12,7 @@ export const NATIONAL_REPORT_CARD_LANDING = export const AREA_OF_INTEREST = 'location/AREA_OF_INTEREST'; export const MAP_IFRAME = 'location/MAP_IFRAME'; export const DASHBOARD = 'location/DASHBOARD'; +export const DASHBOARD_TRENDS = 'location/DASHBOARD_TRENDS'; export const routes: RoutesMap<{ path: string; page?: string }> = { [LANDING]: { @@ -38,6 +39,10 @@ export const routes: RoutesMap<{ path: string; page?: string }> = { path: '/aoi/:id?', page: 'aoi', }, + [DASHBOARD_TRENDS]: { + path: '/dashboard/:iso/:trends?', + page: 'dashboard-trends', + }, [DASHBOARD]: { path: '/dashboard/:iso', page: 'dashboard', From 9e6add3de30320171d6b15d631c28ec68a19838a Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 20 Jun 2024 11:20:00 -0400 Subject: [PATCH 018/350] placeholder for temporal trends charts --- .../score-distributions-component.jsx | 35 --------- .../score-distributions-styles.module.scss | 66 ---------------- .../temporal-trends-component.jsx | 45 ----------- .../temporal-trends-styles.module.scss | 66 ---------------- .../dashboard-trends-sidebar-component.jsx | 22 ++++++ ...ashboard-trends-sidebar-styles.module.scss | 75 +++++++++++++++++++ .../dashboard-trends-sidebar/index.js | 11 +++ .../score-distributions/index.js | 0 .../score-distributions-component.jsx | 34 +++++++++ .../score-distributions-styles.module.scss | 4 + .../dashboard-trends-sidebar/selectors.js | 0 .../temporal-trends/index.js | 0 .../temporal-trends-chart/index.js | 9 +++ .../temporal-trends-chart-component.jsx | 71 ++++++++++++++++++ .../temporal-trends-chart-styles.module.scss | 65 ++++++++++++++++ .../temporal-trends-component.jsx | 47 ++++++++++++ .../temporal-trends-styles.module.scss | 4 + .../dashboard-trends-view-component.jsx | 10 ++- 18 files changed, 348 insertions(+), 216 deletions(-) delete mode 100644 src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx delete mode 100644 src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss delete mode 100644 src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx delete mode 100644 src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-styles.module.scss create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/index.js rename src/containers/sidebars/{dashboard-sidebar => dashboard-trends-sidebar}/score-distributions/index.js (100%) create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-component.jsx create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-styles.module.scss create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/selectors.js rename src/containers/sidebars/{dashboard-sidebar => dashboard-trends-sidebar}/temporal-trends/index.js (100%) create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/index.js create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/temporal-trends-chart-component.jsx create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/temporal-trends-chart-styles.module.scss create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-component.jsx create mode 100644 src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-styles.module.scss diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx deleted file mode 100644 index 105c11730..000000000 --- a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-component.jsx +++ /dev/null @@ -1,35 +0,0 @@ -import React from 'react'; - -import Button from 'components/button'; - -import styles from './score-distributions-styles.module.scss'; - -function ScoreDistributionsComponent() { - return ( -
-
-
- Score Distributions -
-
-

- View the distribution of the individual Species Protection Scores for - all terrestrial vertebrates. Amphibians have the lowest average - protection score while birds have the highest. -

-
-
-
- ); -} - -export default ScoreDistributionsComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss deleted file mode 100644 index 17375b683..000000000 --- a/src/containers/sidebars/dashboard-sidebar/score-distributions/score-distributions-styles.module.scss +++ /dev/null @@ -1,66 +0,0 @@ -@import 'styles/ui.module'; -@import 'styles/settings'; -@import 'styles/typography-extends'; -@import 'styles/common-animations.module'; - -.temporalTrends{ - display: flex; - flex-direction: column; - padding: $paragraph-gutter; - - .title{ - display: flex; - gap: 10px; - - img{ - width: 130px; - height: 130px; - margin-top: 8px; - } - - .info{ - display: flex; - flex-direction: column; - gap: 3px; - color: $white; - margin: 0 0 $site-gutter / 2 0; - - .commonName{ - @extend %display1; - font-size: 24px; - line-height: 1.5; - } - } - } - - .description { - @extend %bodyText; - color: $white; - margin: 0 0 $site-gutter / 2 0; - font-size: 14px; - } - - .options{ - display: flex; - flex-direction: column; - row-gap: 8px; - margin-top: 10px; - - .saveButton { - color: $dark-text; - background-color: $brand-color-main; - &:hover { - background-color: $brand-color-main-hover; - } - } - - .helpText{ - color: #FFF; - font-family: "Open Sans"; - font-size: 9px; - font-style: italic; - font-weight: 400; - line-height: normal; - } - } -} diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx deleted file mode 100644 index db071073b..000000000 --- a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-component.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import React from 'react'; - -import Button from 'components/button'; - -import styles from './temporal-trends-styles.module.scss'; - -function TemporalTrendsComponent() { - return ( -
-
-
- Temporal Trends -
-
-

- Since 1980, the Democratic Republic of the Congo has added 328357 km2 of - land into its protected area network, representing 14% of the total land - in the country, increasing its Species Protection Index from 27.21 in - 1980 to 63 in 2023. -

-
-
-
- ); -} - -export default TemporalTrendsComponent; diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss deleted file mode 100644 index 17375b683..000000000 --- a/src/containers/sidebars/dashboard-sidebar/temporal-trends/temporal-trends-styles.module.scss +++ /dev/null @@ -1,66 +0,0 @@ -@import 'styles/ui.module'; -@import 'styles/settings'; -@import 'styles/typography-extends'; -@import 'styles/common-animations.module'; - -.temporalTrends{ - display: flex; - flex-direction: column; - padding: $paragraph-gutter; - - .title{ - display: flex; - gap: 10px; - - img{ - width: 130px; - height: 130px; - margin-top: 8px; - } - - .info{ - display: flex; - flex-direction: column; - gap: 3px; - color: $white; - margin: 0 0 $site-gutter / 2 0; - - .commonName{ - @extend %display1; - font-size: 24px; - line-height: 1.5; - } - } - } - - .description { - @extend %bodyText; - color: $white; - margin: 0 0 $site-gutter / 2 0; - font-size: 14px; - } - - .options{ - display: flex; - flex-direction: column; - row-gap: 8px; - margin-top: 10px; - - .saveButton { - color: $dark-text; - background-color: $brand-color-main; - &:hover { - background-color: $brand-color-main-hover; - } - } - - .helpText{ - color: #FFF; - font-family: "Open Sans"; - font-size: 9px; - font-style: italic; - font-weight: 400; - line-height: normal; - } - } -} diff --git a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx new file mode 100644 index 000000000..7ddde0818 --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx @@ -0,0 +1,22 @@ +import React from 'react'; + +import styles from './dashboard-trends-sidebar-styles.module.scss'; +import ScoreDistributionsContainer from './score-distributions'; +import TemporalTrendsContainer from './temporal-trends'; + +function DashboardTrendsSidebar(props) { + const { activeLayers, map, view } = props; + + return ( +
+ + +
+ ); +} + +export default DashboardTrendsSidebar; diff --git a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-styles.module.scss b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-styles.module.scss new file mode 100644 index 000000000..030bb1764 --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-styles.module.scss @@ -0,0 +1,75 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +$top: calc(#{$sidebar-top-margin} + #{$he-project-logo-size}); +$trends-width: 950px; + +.container { + @extend %verticalScrollbar; + @include backdropBlur(); + position: absolute; + top: $top; + left: $site-gutter; + display: flex; + flex-direction: column; + border: $sidebar-border; + border-radius: $sidebar-border-radius; + height: calc(100vh - #{$top}); + width: $trends-width; + z-index: $bring-to-front; +} + + +$info-width: 310px; + +.trends{ + display: flex; + padding: $paragraph-gutter; + + .info{ + width: $info-width; + + .title{ + @extend %display1; + display: flex; + gap: 10px; + color: $white; + margin: 0 0 $site-gutter / 2 0; + font-size: 24px; + line-height: 1.5; + } + + .description { + @extend %bodyText; + color: $white; + margin: 0 0 $site-gutter / 2 0; + font-size: 14px; + } + + .options{ + display: flex; + flex-direction: column; + row-gap: 8px; + margin-top: 10px; + + .saveButton { + color: $dark-text; + background-color: $brand-color-main; + &:hover { + background-color: $brand-color-main-hover; + } + } + + .helpText{ + color: #FFF; + font-family: "Open Sans"; + font-size: 9px; + font-style: italic; + font-weight: 400; + line-height: normal; + } + } + } +} diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js new file mode 100644 index 000000000..b907870c7 --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -0,0 +1,11 @@ +import React from 'react'; +import { connect } from 'react-redux'; + +import Component from './dashboard-trends-sidebar-component.jsx'; +import mapStateToProps from './selectors'; + +function DashboardTrendsSidebarContainer() { + return ; +} + +export default connect(mapStateToProps, null)(DashboardTrendsSidebarContainer); diff --git a/src/containers/sidebars/dashboard-sidebar/score-distributions/index.js b/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/index.js similarity index 100% rename from src/containers/sidebars/dashboard-sidebar/score-distributions/index.js rename to src/containers/sidebars/dashboard-trends-sidebar/score-distributions/index.js diff --git a/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-component.jsx new file mode 100644 index 000000000..e9730da24 --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-component.jsx @@ -0,0 +1,34 @@ +import React from 'react'; + +import Button from 'components/button'; + +import styles from '../dashboard-trends-sidebar-styles.module.scss'; + +function ScoreDistributionsComponent() { + return ( +
+
+ Score Distributions + +

+ View the distribution of the individual Species Protection Scores for + all terrestrial vertebrates. Amphibians have the lowest average + protection score while birds have the highest. +

+
+
+
+
+ ); +} + +export default ScoreDistributionsComponent; diff --git a/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-styles.module.scss b/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-styles.module.scss new file mode 100644 index 000000000..c709bfc60 --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/score-distributions/score-distributions-styles.module.scss @@ -0,0 +1,4 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; diff --git a/src/containers/sidebars/dashboard-trends-sidebar/selectors.js b/src/containers/sidebars/dashboard-trends-sidebar/selectors.js new file mode 100644 index 000000000..e69de29bb diff --git a/src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js b/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/index.js similarity index 100% rename from src/containers/sidebars/dashboard-sidebar/temporal-trends/index.js rename to src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/index.js diff --git a/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/index.js b/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/index.js new file mode 100644 index 000000000..49238c4cb --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import TemporalTrendsChartComponent from './temporal-trends-chart-component'; + +function TemporalTrendsChartContainer(props) { + return ; +} + +export default TemporalTrendsChartContainer; diff --git a/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/temporal-trends-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/temporal-trends-chart-component.jsx new file mode 100644 index 000000000..f8e1d2dfd --- /dev/null +++ b/src/containers/sidebars/dashboard-trends-sidebar/temporal-trends/temporal-trends-chart/temporal-trends-chart-component.jsx @@ -0,0 +1,71 @@ +import React from 'react'; +import Select from 'react-select'; + +import ArcChart from 'components/charts/arc-chart'; + +import COLORS from 'styles/settings'; + +import styles from './temporal-trends-chart-styles.module.scss'; + +function TemporalTrendsChartComponent() { + const areaChartHeight = 100; + const areaChartWidth = 220; + const spi = 48.55; + + const provinces = [ + { value: 'Mai-Ndombe', label: 'Mai-Ndombe' }, + { value: 'Équateur', label: 'Équateur' }, + { value: 'Kasaï', label: 'Kasaï' }, + { value: 'Sankuru', label: 'Sankuru' }, + ]; + + return ( +
+
+ - - #13 in Species Protection Index - - - #1 in vertebrate species richness - - - #16 in size - -
-
-
- 2024 - Year -
-
- +
+
+ + {shiCountries.map(item => ( + + ))} + +
+
+ + + +
+
+
+ +
+ +
+ {chartData && } + {habitatTableData.length && + + + + + + + + + + + + {habitatTableData.map(row => ( + updateCountry({ value: row.country })} + className={(selectedCountry === row.country || countryName === row.country) ? styles.highlighted : ''} + > + + + + + + + ))} + +
CountryStewardshipConnectivity ScoreArea ScoreTotal SHS
{row.country}{row.stewardship.toFixed(2)}% + {(row.countryConnectivityScore * 100).toFixed(2)} + + {(row.countryAreaScore * 100).toFixed(2)} + {row.shs.toFixed(2)}%
+ } +
+
+ ) +} + +export default HabitatComponent diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/index.js b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/index.js new file mode 100644 index 000000000..62a08bd33 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/index.js @@ -0,0 +1,9 @@ +import React from 'react'; + +import HabitatComponent from './habitat-component'; + +function HabitatContainer(props) { + return ; +} + +export default HabitatContainer; diff --git a/src/containers/sidebars/dashboard-sidebar/index.js b/src/containers/sidebars/dashboard-sidebar/index.js index 6bcb7c8e3..e74127ad4 100644 --- a/src/containers/sidebars/dashboard-sidebar/index.js +++ b/src/containers/sidebars/dashboard-sidebar/index.js @@ -7,18 +7,14 @@ import mapStateToProps from './selectors'; function DashboardSidebarContainer(props) { const {scientificName, countryName} = props; - const [data, setData] = useState({}); - const [dataByCountry, setDataByCountry] = useState({frag: [], shs: []}); + const [data, setData] = useState(null); + const [dataByCountry, setDataByCountry] = useState(null); useEffect(() => { getData(); }, [scientificName]); - useEffect(() => { - const habitatScore = getHabitatScore(); - console.log(habitatScore); - }, [dataByCountry]) const getData = async () => { const speciesPreferences = `https://next-api-dot-api-2-x-dot-map-of-life.appspot.com/2.x/species/habitat?scientificname=${scientificName}`; @@ -87,42 +83,7 @@ function DashboardSidebarContainer(props) { setDataByCountry(countryData); } - const getHabitatScore = () => { - const country = dataByCountry[countryName]; - - // const countrySHS = country?.shs; - const startYearValue = country?.frag[0].gisfrag; - // eslint-disable-next-line no-unsafe-optional-chaining - const lastCountryYearValue = country?.shs.length - 1; - - const { countryAreaScore, countryConnectivityScore } = getCountryScores(country, lastCountryYearValue, startYearValue); - - // if (dataByCountry.Global?.shs[lastCountryYearValue]) { - // this.globalAreaScore = this.dataByCountry.Global?.shs[this.lastCountryYearValue].propchange; - // this.globalConnectivityScore = ( - // // eslint-disable-next-line no-unsafe-optional-chaining - // this.dataByCountry.Global?.frag[this.lastCountryYearValue].gisfrag / this.startYearValue - // ); - // } - - return ((countryAreaScore + countryConnectivityScore) / 2) * 100; - // this.globalHabitatScore = ((this.globalAreaScore + this.globalConnectivityScore) / 2) * 100; - } - - const getCountryScores = (country, lastCountryYearValue, startYearValue) => { - if (country?.shs[lastCountryYearValue]) { - const countryAreaScore = country?.shs[lastCountryYearValue].propchange; - const countryConnectivityScore = ( - // eslint-disable-next-line no-unsafe-optional-chaining - country?.frag[lastCountryYearValue]?.gisfrag / startYearValue - ); - - return { countryAreaScore, countryConnectivityScore }; - } - return { countryAreaScore: 0, countryConnectivityScore: 0 }; - } - - return ; + return ; } export default connect(mapStateToProps, null)(DashboardSidebarContainer); diff --git a/src/containers/sidebars/dashboard-sidebar/mol-country-attributes.json b/src/containers/sidebars/dashboard-sidebar/mol-country-attributes.json new file mode 100644 index 000000000..48d3c3081 --- /dev/null +++ b/src/containers/sidebars/dashboard-sidebar/mol-country-attributes.json @@ -0,0 +1 @@ +[{"GEO_ID":1,"ISO3":"ABW","NAME":"Aruba","REGION_ID":"fee99b31-465c-4edc-acbe-0ca31cce4d0e"},{"GEO_ID":2,"ISO3":"AFG","NAME":"Afghanistan","REGION_ID":"f1b0a8bd-ccbc-43ad-82c6-d665598fcbf7"},{"GEO_ID":3,"ISO3":"AGO","NAME":"Angola","REGION_ID":"a01885ee-84fa-4ccd-a4af-feedeb02750c"},{"GEO_ID":4,"ISO3":"AIA","NAME":"Anguilla","REGION_ID":"eb9a67f8-c6ee-4bf1-a310-c41c1fcf1704"},{"GEO_ID":5,"ISO3":"ALA","NAME":"Åland","REGION_ID":"6f680399-366c-41a1-be03-3c70d06fbfe6"},{"GEO_ID":6,"ISO3":"ALB","NAME":"Albania","REGION_ID":"910dd100-dd79-467d-a6a1-0fdfd49ac6d4"},{"GEO_ID":7,"ISO3":"AND","NAME":"Andorra","REGION_ID":"24971000-3230-4eab-9866-5ae8ff7ed2a8"},{"GEO_ID":8,"ISO3":"ARE","NAME":"United Arab Emirates","REGION_ID":"01f5669a-bd35-46eb-b4d6-48b1e00296fd"},{"GEO_ID":9,"ISO3":"ARG","NAME":"Argentina","REGION_ID":"897d05e6-6dfc-426c-927c-99bbb5218a77"},{"GEO_ID":10,"ISO3":"ARM","NAME":"Armenia","REGION_ID":"a7969e69-adaa-40d8-ba02-cbdd98084a78"},{"GEO_ID":11,"ISO3":"ASM","NAME":"American Samoa","REGION_ID":"2f4eb1ad-4698-494e-a01e-97c9544b31ab"},{"GEO_ID":12,"ISO3":"ATA","NAME":"Antarctica","REGION_ID":"9fb0cae7-ee8f-4475-89c0-bc1c64b87db6"},{"GEO_ID":13,"ISO3":"ATF","NAME":"French Southern Territories","REGION_ID":"9b86c26a-8230-4c59-8464-db0865abbb0c"},{"GEO_ID":14,"ISO3":"ATG","NAME":"Antigua and Barbuda","REGION_ID":"ad0f6204-f4dd-4aa9-80e2-5d52016a4d06"},{"GEO_ID":15,"ISO3":"AUS","NAME":"Australia","REGION_ID":"52113000-c475-4db4-a46c-3203ba706054"},{"GEO_ID":16,"ISO3":"AUT","NAME":"Austria","REGION_ID":"0c89fafd-0896-4abd-a5fe-c41cdb4ac4ac"},{"GEO_ID":17,"ISO3":"AZE","NAME":"Azerbaijan","REGION_ID":"42b69ecf-0f24-40c4-b493-ffabea3c4ce3"},{"GEO_ID":18,"ISO3":"BDI","NAME":"Burundi","REGION_ID":"4771400a-f813-44be-953b-c4a5a17b0877"},{"GEO_ID":19,"ISO3":"BEL","NAME":"Belgium","REGION_ID":"85f90819-4add-484b-b980-284882a7635d"},{"GEO_ID":20,"ISO3":"BEN","NAME":"Benin","REGION_ID":"f00533f8-4726-40b9-af1e-d40ffee23b0d"},{"GEO_ID":21,"ISO3":"BES","NAME":"Bonaire, Sint Eustatius and Saba","REGION_ID":"82721b3b-390d-4462-95a9-f02f03aff561"},{"GEO_ID":22,"ISO3":"BFA","NAME":"Burkina Faso","REGION_ID":"c189ad16-8f17-4b77-9ae0-4e04a230acdd"},{"GEO_ID":23,"ISO3":"BGD","NAME":"Bangladesh","REGION_ID":"979aa058-c5d2-4ba0-9879-d68387542dff"},{"GEO_ID":24,"ISO3":"BGR","NAME":"Bulgaria","REGION_ID":"99986896-05e9-403f-be52-afd6407f6a6a"},{"GEO_ID":25,"ISO3":"BHR","NAME":"Bahrain","REGION_ID":"a5ab7864-ba9d-4147-b054-1ffbe4153ed0"},{"GEO_ID":26,"ISO3":"BHS","NAME":"Bahamas","REGION_ID":"007d3ec6-b50d-4ad2-963b-e82d3e6e25e8"},{"GEO_ID":27,"ISO3":"BIH","NAME":"Bosnia and Herzegovina","REGION_ID":"598adc43-b1b3-4eed-b951-4a122b509ac2"},{"GEO_ID":28,"ISO3":"BLM","NAME":"Saint-Barthélemy","REGION_ID":"8e3b3c8a-112f-477a-95c9-7ccdfc5505d7"},{"GEO_ID":29,"ISO3":"BLR","NAME":"Belarus","REGION_ID":"b9706318-c602-4c94-8fec-707b818774a2"},{"GEO_ID":30,"ISO3":"BLZ","NAME":"Belize","REGION_ID":"7524378b-e95d-4afe-9954-6e97ddfbdaf8"},{"GEO_ID":31,"ISO3":"BMU","NAME":"Bermuda","REGION_ID":"78172139-419d-4b5b-89ce-3a2d1bc3dd6f"},{"GEO_ID":32,"ISO3":"BOL","NAME":"Bolivia","REGION_ID":"b324f90b-25f5-4ad0-86b7-0bf39eea64f8"},{"GEO_ID":33,"ISO3":"BRA","NAME":"Brazil","REGION_ID":"ca3e23e7-1d60-464e-9e1a-61ae9e1cb006"},{"GEO_ID":34,"ISO3":"BRB","NAME":"Barbados","REGION_ID":"2d6e1b52-5620-416d-b6dc-b6b885508a8f"},{"GEO_ID":35,"ISO3":"BRN","NAME":"Brunei","REGION_ID":"83a421a3-6da2-4c89-9af5-5170b3085d6f"},{"GEO_ID":36,"ISO3":"BTN","NAME":"Bhutan","REGION_ID":"b58ab549-4ee2-47c6-a611-ca0c30ec94fd"},{"GEO_ID":37,"ISO3":"BVT","NAME":"Bouvet Island","REGION_ID":"31592207-25e0-471d-a8ee-e0f624cd5f38"},{"GEO_ID":38,"ISO3":"BWA","NAME":"Botswana","REGION_ID":"794637ce-4182-44b7-bf5b-b7dd625ade74"},{"GEO_ID":39,"ISO3":"CAF","NAME":"Central African Republic","REGION_ID":"d286bae6-afee-43a3-a490-d13356c0057f"},{"GEO_ID":40,"ISO3":"CAN","NAME":"Canada","REGION_ID":"8c90cf0d-2b0c-42ab-864d-43ff2f7f1145"},{"GEO_ID":41,"ISO3":"CCK","NAME":"Cocos Islands","REGION_ID":"b5de4439-9143-4ef8-8e57-e04b1c132af6"},{"GEO_ID":42,"ISO3":"CHE","NAME":"Switzerland","REGION_ID":"1121bb2d-fd3e-49ea-8e61-e5b4aab8a538"},{"GEO_ID":43,"ISO3":"CHL","NAME":"Chile","REGION_ID":"f8207868-1091-4e18-9680-e6e54220fd22"},{"GEO_ID":44,"ISO3":"CHN","NAME":"China","REGION_ID":"10befcf4-155b-46ef-a6a8-ca3a8e68fd19"},{"GEO_ID":45,"ISO3":"CIV","NAME":"Côte d'Ivoire","REGION_ID":"ce75cfca-a5e8-44e6-95a3-1467e26b4639"},{"GEO_ID":46,"ISO3":"CMR","NAME":"Cameroon","REGION_ID":"3fda604a-28a1-40ae-93b5-4e852c398e09"},{"GEO_ID":47,"ISO3":"COD","NAME":"Democratic Republic of the Congo","REGION_ID":"90b03e87-3880-4164-a310-339994e3f919"},{"GEO_ID":48,"ISO3":"COG","NAME":"Republic of Congo","REGION_ID":"0c98b276-f38a-4a2e-abab-0acfad46ac69"},{"GEO_ID":49,"ISO3":"COK","NAME":"Cook Islands","REGION_ID":"dcc14246-ee6e-4a5e-abff-2216536894b4"},{"GEO_ID":50,"ISO3":"COL","NAME":"Colombia","REGION_ID":"5eeefdc1-03d2-4686-a447-d79402a93425"},{"GEO_ID":51,"ISO3":"COM","NAME":"Comoros","REGION_ID":"ec7907ed-6de5-4f63-b570-beba1207baa5"},{"GEO_ID":52,"ISO3":"CPV","NAME":"Cape Verde","REGION_ID":"1a45fe3b-6b5f-4ab4-9a3a-7c901bd8c357"},{"GEO_ID":53,"ISO3":"CRI","NAME":"Costa Rica","REGION_ID":"fba67d08-ee5d-4d7f-a5ab-4ddd7be134df"},{"GEO_ID":54,"ISO3":"CUB","NAME":"Cuba","REGION_ID":"15ba9e24-fac6-465c-a5d1-0034cdf7456f"},{"GEO_ID":55,"ISO3":"CUW","NAME":"Curaçao","REGION_ID":"46cf7bba-1db8-45d0-a8ca-c47d22d2e48c"},{"GEO_ID":56,"ISO3":"CXR","NAME":"Christmas Island","REGION_ID":"c505d69a-9382-4a65-9b37-38190c619675"},{"GEO_ID":57,"ISO3":"CYM","NAME":"Cayman Islands","REGION_ID":"6a560fd5-59ef-4426-bfee-7801c9c6fbd6"},{"GEO_ID":58,"ISO3":"CYP","NAME":"Cyprus","REGION_ID":"f86004b3-d504-4934-92d8-92ef2f808492"},{"GEO_ID":59,"ISO3":"CZE","NAME":"Czech Republic","REGION_ID":"00f56e11-6f89-4b61-8a65-62f722c8b738"},{"GEO_ID":60,"ISO3":"DEU","NAME":"Germany","REGION_ID":"48dbf7cf-b380-4c33-8a4d-5b8c892d710f"},{"GEO_ID":61,"ISO3":"DJI","NAME":"Djibouti","REGION_ID":"e1454f19-ee49-4268-a4f7-c0314914f48a"},{"GEO_ID":62,"ISO3":"DMA","NAME":"Dominica","REGION_ID":"a234c9da-5dfa-4171-8ebe-2dcb8faf2358"},{"GEO_ID":63,"ISO3":"DNK","NAME":"Denmark","REGION_ID":"d6ab9c75-0607-41ed-9f7e-64213f853cba"},{"GEO_ID":64,"ISO3":"DOM","NAME":"Dominican Republic","REGION_ID":"6529d262-30b0-4dc2-ac8c-b14db4760c2d"},{"GEO_ID":65,"ISO3":"DZA","NAME":"Algeria","REGION_ID":"96abdaec-88f3-43d0-9193-fcb36d7f05c8"},{"GEO_ID":66,"ISO3":"ECU","NAME":"Ecuador","REGION_ID":"820244c0-44c5-4fe3-81d3-f01556fde5c5"},{"GEO_ID":67,"ISO3":"EGY","NAME":"Egypt","REGION_ID":"5ea33967-35d9-4ca4-b1fa-9b3f10f53641"},{"GEO_ID":68,"ISO3":"ERI","NAME":"Eritrea","REGION_ID":"fb302f98-520b-45ac-9334-96de07f93c78"},{"GEO_ID":69,"ISO3":"ESH","NAME":"Western Sahara","REGION_ID":"880c22a0-9375-48e6-b208-7c3af0663c44"},{"GEO_ID":70,"ISO3":"ESP","NAME":"Spain","REGION_ID":"15393966-6b57-4447-9f0c-e50077c516d4"},{"GEO_ID":71,"ISO3":"EST","NAME":"Estonia","REGION_ID":"f72e2031-af5e-4fa6-af37-e4309936742f"},{"GEO_ID":72,"ISO3":"ETH","NAME":"Ethiopia","REGION_ID":"b74ac2e3-f8ca-4d46-81b9-f1a685ba0657"},{"GEO_ID":73,"ISO3":"FIN","NAME":"Finland","REGION_ID":"eae62a5b-f89a-4f84-98c2-f9efc3e2ca97"},{"GEO_ID":74,"ISO3":"FJI","NAME":"Fiji","REGION_ID":"52423050-b862-400f-b944-ec49b8f8e261"},{"GEO_ID":75,"ISO3":"FLK","NAME":"Falkland Islands","REGION_ID":"d21a9cb7-32dc-415f-a555-6d6dbf9ae948"},{"GEO_ID":76,"ISO3":"FRA","NAME":"France","REGION_ID":"4a400958-7ee5-4619-b1e9-5f0b2469e349"},{"GEO_ID":77,"ISO3":"FRO","NAME":"Faroe Islands","REGION_ID":"3e07160b-9ebc-408e-9d4c-3d37b7044688"},{"GEO_ID":78,"ISO3":"FSM","NAME":"Micronesia","REGION_ID":"97d0b1f9-cc34-4614-9ef4-5499ea67dcab"},{"GEO_ID":79,"ISO3":"GAB","NAME":"Gabon","REGION_ID":"30810b40-0044-46dd-a1cd-5a3217749738"},{"GEO_ID":80,"ISO3":"GBR","NAME":"United Kingdom","REGION_ID":"21a8e228-fc67-4e87-96bd-ee7f8beaeb47"},{"GEO_ID":81,"ISO3":"GEO","NAME":"Georgia","REGION_ID":"7eb6c4ea-688f-428e-9924-5821b106df77"},{"GEO_ID":82,"ISO3":"GGY","NAME":"Guernsey","REGION_ID":"64b547cb-8318-4284-a061-b6edb52efe84"},{"GEO_ID":83,"ISO3":"GHA","NAME":"Ghana","REGION_ID":"43fd0520-1126-45d2-8dd4-ca9bcbf27735"},{"GEO_ID":84,"ISO3":"GIB","NAME":"Gibraltar","REGION_ID":"f4d513e0-cfa7-490b-93b0-e186e17b0fc9"},{"GEO_ID":85,"ISO3":"GIN","NAME":"Guinea","REGION_ID":"22200606-e907-497f-96db-e7cfd95d61b5"},{"GEO_ID":86,"ISO3":"GLP","NAME":"Guadeloupe","REGION_ID":"e10b34e0-c00e-4752-b023-0ca37bf0767f"},{"GEO_ID":87,"ISO3":"GMB","NAME":"Gambia","REGION_ID":"dc86208f-3e05-4fa2-8a61-19c2ba90b903"},{"GEO_ID":88,"ISO3":"GNB","NAME":"Guinea-Bissau","REGION_ID":"15c15d29-31f0-47cd-b22d-38ffc3764b84"},{"GEO_ID":89,"ISO3":"GNQ","NAME":"Equatorial Guinea","REGION_ID":"35657c66-a459-4131-a767-348bb2687742"},{"GEO_ID":90,"ISO3":"GRC","NAME":"Greece","REGION_ID":"a8511cc6-dd5e-4616-a045-32031f3a86ac"},{"GEO_ID":91,"ISO3":"GRD","NAME":"Grenada","REGION_ID":"7cef5f1a-3dbe-4a59-be66-c550ad4dced9"},{"GEO_ID":92,"ISO3":"GRL","NAME":"Greenland","REGION_ID":"73f872b4-7723-41db-be54-7ce29919357c"},{"GEO_ID":93,"ISO3":"GTM","NAME":"Guatemala","REGION_ID":"6e20d4c8-9c19-4cbd-b8ac-96107776a65e"},{"GEO_ID":94,"ISO3":"GUF","NAME":"French Guiana","REGION_ID":"2a779654-4086-430a-89e0-8dcb54772845"},{"GEO_ID":95,"ISO3":"GUM","NAME":"Guam","REGION_ID":"87a30e40-4c04-487a-acae-3b35c9ba4728"},{"GEO_ID":96,"ISO3":"GUY","NAME":"Guyana","REGION_ID":"25ca0de8-c215-4cda-aafd-f6d644ed9e4a"},{"GEO_ID":97,"ISO3":"HKG","NAME":"Hong Kong","REGION_ID":"f1ea9f6f-b616-49c4-a1a8-6b0ee7d032bf"},{"GEO_ID":98,"ISO3":"HMD","NAME":"Heard Island and McDonald Islands","REGION_ID":"de029d28-87a9-4cb5-ad0e-de8d82fe6529"},{"GEO_ID":99,"ISO3":"HND","NAME":"Honduras","REGION_ID":"933013bd-2a70-44f4-83a7-d3c1f4086cbd"},{"GEO_ID":100,"ISO3":"HRV","NAME":"Croatia","REGION_ID":"9b794015-a7c8-4a2b-b7a0-12dded43b3f9"},{"GEO_ID":101,"ISO3":"HTI","NAME":"Haiti","REGION_ID":"f447037c-09cf-47f3-be49-c260544c3aa1"},{"GEO_ID":102,"ISO3":"HUN","NAME":"Hungary","REGION_ID":"5647081c-7f77-4a3d-962f-2c39d66b0be5"},{"GEO_ID":103,"ISO3":"IDN","NAME":"Indonesia","REGION_ID":"3ccb99e1-0f2c-4ed9-a35b-3fbcfaa5ed11"},{"GEO_ID":104,"ISO3":"IMN","NAME":"Isle of Man","REGION_ID":"fcd94225-2fc6-4a2a-8017-4621a392b192"},{"GEO_ID":105,"ISO3":"IND","NAME":"India","REGION_ID":"7410608a-f752-4b63-9698-34f2a0ce4eb3"},{"GEO_ID":106,"ISO3":"IOT","NAME":"British Indian Ocean Territory","REGION_ID":"aca525ef-0ede-4ce7-9de2-fba79b1f418f"},{"GEO_ID":107,"ISO3":"IRL","NAME":"Ireland","REGION_ID":"59eae850-c83f-4927-aa41-195e50bc9bc7"},{"GEO_ID":108,"ISO3":"IRN","NAME":"Iran","REGION_ID":"fdee96ad-6852-4f1a-9760-84ae8e92e001"},{"GEO_ID":109,"ISO3":"IRQ","NAME":"Iraq","REGION_ID":"106a1e38-0ced-461a-886b-1f1248c09b5f"},{"GEO_ID":110,"ISO3":"ISL","NAME":"Iceland","REGION_ID":"db119bef-4f14-4315-9647-bf7c77125e8a"},{"GEO_ID":111,"ISO3":"ISR","NAME":"Israel","REGION_ID":"7ffaa41d-1d6b-4595-8ca4-2e8d4878da54"},{"GEO_ID":112,"ISO3":"ITA","NAME":"Italy","REGION_ID":"22c5e5d3-b096-40fb-8982-5a3a2c3396f3"},{"GEO_ID":113,"ISO3":"JAM","NAME":"Jamaica","REGION_ID":"d3e41119-d06c-4ece-adcb-aa4afe7b3de5"},{"GEO_ID":114,"ISO3":"JEY","NAME":"Jersey","REGION_ID":"c99a8cf8-6150-46f9-84a8-9d6276fe396b"},{"GEO_ID":115,"ISO3":"JOR","NAME":"Jordan","REGION_ID":"fc3b331c-f81d-4bb4-a7aa-d8973247dce2"},{"GEO_ID":116,"ISO3":"JPN","NAME":"Japan","REGION_ID":"aa03f64e-0044-485f-9371-e6730ef97dee"},{"GEO_ID":117,"ISO3":"KAZ","NAME":"Kazakhstan","REGION_ID":"2cffda41-307f-4a2c-b675-04a4794b3e5a"},{"GEO_ID":118,"ISO3":"KEN","NAME":"Kenya","REGION_ID":"f839d936-e194-4a3a-b6e8-1812a7b4f827"},{"GEO_ID":119,"ISO3":"KGZ","NAME":"Kyrgyzstan","REGION_ID":"8d385ef3-735f-4e59-b986-b814a59beedd"},{"GEO_ID":120,"ISO3":"KHM","NAME":"Cambodia","REGION_ID":"40be0146-9389-41f5-a733-0d7d1863da49"},{"GEO_ID":121,"ISO3":"KIR","NAME":"Kiribati","REGION_ID":"2095b81b-bb09-461c-a05b-9255f010c4e8"},{"GEO_ID":122,"ISO3":"KNA","NAME":"Saint Kitts and Nevis","REGION_ID":"4d3a087c-aa07-4c4b-a0c6-8250a567efff"},{"GEO_ID":123,"ISO3":"KOR","NAME":"South Korea","REGION_ID":"90acab3e-5a1e-432e-abf2-e09f42ab3fc1"},{"GEO_ID":124,"ISO3":"KWT","NAME":"Kuwait","REGION_ID":"8ae9cbeb-0c40-4f20-b95f-059f785bddf0"},{"GEO_ID":125,"ISO3":"LAO","NAME":"Laos","REGION_ID":"905bbee6-1713-4a73-8192-93b3bf58a611"},{"GEO_ID":126,"ISO3":"LBN","NAME":"Lebanon","REGION_ID":"cc32db84-5638-49d5-9acc-804db1fce973"},{"GEO_ID":127,"ISO3":"LBR","NAME":"Liberia","REGION_ID":"50e1557e-fc47-481a-b090-66d5cba5be70"},{"GEO_ID":128,"ISO3":"LBY","NAME":"Libya","REGION_ID":"cbb78d4b-7d5b-4869-abf8-93a2079143ef"},{"GEO_ID":129,"ISO3":"LCA","NAME":"Saint Lucia","REGION_ID":"bd644c87-31dd-422f-9462-4669fb83f652"},{"GEO_ID":130,"ISO3":"LIE","NAME":"Liechtenstein","REGION_ID":"3429fc32-b221-4a24-b35a-98a57098eeb4"},{"GEO_ID":131,"ISO3":"LKA","NAME":"Sri Lanka","REGION_ID":"57921c75-d2bd-4b57-9618-f5b9061954e5"},{"GEO_ID":132,"ISO3":"LSO","NAME":"Lesotho","REGION_ID":"42a0f001-470f-4e3f-9eed-fe27b2b716fe"},{"GEO_ID":133,"ISO3":"LTU","NAME":"Lithuania","REGION_ID":"922b96b0-9038-4a9b-93dd-a56e8dc5098e"},{"GEO_ID":134,"ISO3":"LUX","NAME":"Luxembourg","REGION_ID":"a258ae26-83da-4acd-a762-d5e44ea0fa66"},{"GEO_ID":135,"ISO3":"LVA","NAME":"Latvia","REGION_ID":"c883de73-23f4-4a52-b42c-b60a8da5eaa1"},{"GEO_ID":136,"ISO3":"MAC","NAME":"Macao","REGION_ID":"be21ece8-003f-4e65-8137-7a94ef9d5bc3"},{"GEO_ID":137,"ISO3":"MAF","NAME":"Saint-Martin","REGION_ID":"8a9a037f-b077-4751-bb10-218f89e60d87"},{"GEO_ID":138,"ISO3":"MAR","NAME":"Morocco","REGION_ID":"96ece8fa-cdf8-41cb-8b7a-473559652f93"},{"GEO_ID":139,"ISO3":"MCO","NAME":"Monaco","REGION_ID":"ed4a7687-4f95-4cfe-86f4-c2a388e9246d"},{"GEO_ID":140,"ISO3":"MDA","NAME":"Moldova","REGION_ID":"a3b7cdc4-8707-428b-b303-2e0767462329"},{"GEO_ID":141,"ISO3":"MDG","NAME":"Madagascar","REGION_ID":"72b6baa0-823b-4116-95aa-d61674de995b"},{"GEO_ID":142,"ISO3":"MDV","NAME":"Maldives","REGION_ID":"b5686747-c24e-4bae-8e2a-de02f2249019"},{"GEO_ID":143,"ISO3":"MEX","NAME":"Mexico","REGION_ID":"7d8e3429-a5b5-42ce-968d-d86106254ff8"},{"GEO_ID":144,"ISO3":"MHL","NAME":"Marshall Islands","REGION_ID":"3a7318fb-94cd-4885-a76a-eebd90ee48ee"},{"GEO_ID":145,"ISO3":"MKD","NAME":"Macedonia","REGION_ID":"6f2a53e6-eb0e-4a6d-8998-d48b45b11e4b"},{"GEO_ID":146,"ISO3":"MLI","NAME":"Mali","REGION_ID":"60fa4f95-7415-47b7-abb3-f86ec028f5f3"},{"GEO_ID":147,"ISO3":"MLT","NAME":"Malta","REGION_ID":"9b6c3861-711a-43a8-8152-205d3cbf7844"},{"GEO_ID":148,"ISO3":"MMR","NAME":"Myanmar","REGION_ID":"d636b801-89a2-4eaf-9d58-4ece3a4d0594"},{"GEO_ID":149,"ISO3":"MNE","NAME":"Montenegro","REGION_ID":"127e5960-7a62-4b2c-ba59-4743da1bc9fe"},{"GEO_ID":150,"ISO3":"MNG","NAME":"Mongolia","REGION_ID":"b5a7cc4f-deda-400c-b48f-e4a24a7604be"},{"GEO_ID":151,"ISO3":"MNP","NAME":"Northern Mariana Islands","REGION_ID":"7cc11db2-dfc5-4bc1-b55a-1959710f3a4b"},{"GEO_ID":152,"ISO3":"MOZ","NAME":"Mozambique","REGION_ID":"9071dde7-4ede-4f50-a649-d5219d9224d2"},{"GEO_ID":153,"ISO3":"MRT","NAME":"Mauritania","REGION_ID":"ea3ae466-cfd7-4e63-9262-bd651c5bab90"},{"GEO_ID":154,"ISO3":"MSR","NAME":"Montserrat","REGION_ID":"ab7acba8-13e7-43a5-9452-0d249327b691"},{"GEO_ID":155,"ISO3":"MTQ","NAME":"Martinique","REGION_ID":"d5867dfa-020e-42ac-b3ca-abac5b4660a3"},{"GEO_ID":156,"ISO3":"MUS","NAME":"Mauritius","REGION_ID":"df8090e3-7f1d-421a-b28b-c135cf848d01"},{"GEO_ID":157,"ISO3":"MWI","NAME":"Malawi","REGION_ID":"f7e0587a-6546-4635-b1b4-cf93d7d60190"},{"GEO_ID":158,"ISO3":"MYS","NAME":"Malaysia","REGION_ID":"e7d859d2-73fc-4a13-b226-fae746c2b885"},{"GEO_ID":159,"ISO3":"MYT","NAME":"Mayotte","REGION_ID":"aa86460a-3d33-4f76-8ccb-b91e22462314"},{"GEO_ID":160,"ISO3":"NAM","NAME":"Namibia","REGION_ID":"f1c5b971-7d97-4135-bf6e-d7e1d03c938e"},{"GEO_ID":161,"ISO3":"NCL","NAME":"New Caledonia","REGION_ID":"072810da-5139-4b0d-a0a3-5243220ad318"},{"GEO_ID":162,"ISO3":"NER","NAME":"Niger","REGION_ID":"26091048-c0c4-4fd6-b8dc-8de60184c3e8"},{"GEO_ID":163,"ISO3":"NFK","NAME":"Norfolk Island","REGION_ID":"c3df8035-0fd3-44a0-8340-ad64c4407b2f"},{"GEO_ID":164,"ISO3":"NGA","NAME":"Nigeria","REGION_ID":"e3a8b6ab-f383-4694-9aa7-0c13877ce4c1"},{"GEO_ID":165,"ISO3":"NIC","NAME":"Nicaragua","REGION_ID":"7c8ac8c1-cd3b-4bcf-8bfc-42b8335ce0e4"},{"GEO_ID":166,"ISO3":"NIU","NAME":"Niue","REGION_ID":"9d3b8c5f-a295-4608-8368-71c27c772a00"},{"GEO_ID":167,"ISO3":"NLD","NAME":"Netherlands","REGION_ID":"121e9800-122d-421e-9005-59da97e0256c"},{"GEO_ID":168,"ISO3":"NOR","NAME":"Norway","REGION_ID":"b49746f5-9d85-46e9-95d8-b4757fe67f54"},{"GEO_ID":169,"ISO3":"NPL","NAME":"Nepal","REGION_ID":"b3a102f6-49b9-4976-83d9-6e2d60fa33ac"},{"GEO_ID":170,"ISO3":"NRU","NAME":"Nauru","REGION_ID":"b3d973cb-55e6-4229-a352-77d18a4d8f98"},{"GEO_ID":171,"ISO3":"NZL","NAME":"New Zealand","REGION_ID":"5379e7a6-063d-41bf-acc2-9f6c25e98caa"},{"GEO_ID":172,"ISO3":"OMN","NAME":"Oman","REGION_ID":"15781f4d-228a-4fcc-be8b-22c693c6c44c"},{"GEO_ID":173,"ISO3":"PAK","NAME":"Pakistan","REGION_ID":"e7161a9b-e35b-45da-b043-3e9c7256a56e"},{"GEO_ID":174,"ISO3":"PAN","NAME":"Panama","REGION_ID":"2869bb42-3828-4cd5-bea4-3bbf97181f4f"},{"GEO_ID":175,"ISO3":"PCN","NAME":"Pitcairn Islands","REGION_ID":"fe1174ce-0a54-4a58-92bd-1db5ed6ee531"},{"GEO_ID":176,"ISO3":"PER","NAME":"Peru","REGION_ID":"d782caea-8e79-40f3-b938-47e3006b0766"},{"GEO_ID":177,"ISO3":"PHL","NAME":"Philippines","REGION_ID":"4f8d1572-0139-412f-8f5f-3561a955cbf1"},{"GEO_ID":178,"ISO3":"PLW","NAME":"Palau","REGION_ID":"e121d7ad-1db2-4851-9a80-aac58612d4b1"},{"GEO_ID":179,"ISO3":"PNG","NAME":"Papua New Guinea","REGION_ID":"48a653ba-9433-4a15-80e6-c356b5d28f42"},{"GEO_ID":180,"ISO3":"POL","NAME":"Poland","REGION_ID":"99e309bf-2876-471e-9510-99cd543291f2"},{"GEO_ID":181,"ISO3":"PRI","NAME":"Puerto Rico","REGION_ID":"22b8bcc2-709b-4684-9935-8c1bc15e376b"},{"GEO_ID":182,"ISO3":"PRK","NAME":"North Korea","REGION_ID":"2ab0886c-8b01-498b-a988-76bc01e99a7e"},{"GEO_ID":183,"ISO3":"PRT","NAME":"Portugal","REGION_ID":"1df34786-540b-46e1-93d1-d7d60eeb54f1"},{"GEO_ID":184,"ISO3":"PRY","NAME":"Paraguay","REGION_ID":"30bd42c0-b3ce-409d-a3fd-87cd1599dc9c"},{"GEO_ID":185,"ISO3":"PSE","NAME":"Palestina","REGION_ID":"db3d3322-bb51-4537-8343-a019bd2915e2"},{"GEO_ID":186,"ISO3":"PYF","NAME":"French Polynesia","REGION_ID":"0d1945f2-a8e6-4cad-a569-2060ddf84405"},{"GEO_ID":187,"ISO3":"QAT","NAME":"Qatar","REGION_ID":"5913271a-8182-4254-9a71-f1f49bddfaa5"},{"GEO_ID":188,"ISO3":"REU","NAME":"Reunion","REGION_ID":"16f4ccaa-f541-4093-b805-97be3d040d13"},{"GEO_ID":189,"ISO3":"ROU","NAME":"Romania","REGION_ID":"954adfc5-3a5d-4cb9-bac8-d8a9bd480cf2"},{"GEO_ID":190,"ISO3":"RUS","NAME":"Russia","REGION_ID":"a091317c-6c52-4c48-a1e3-d5b5bb59bbd7"},{"GEO_ID":191,"ISO3":"RWA","NAME":"Rwanda","REGION_ID":"5bb91b6f-47c2-4d1e-9600-fd6717ca2cb3"},{"GEO_ID":192,"ISO3":"SAU","NAME":"Saudi Arabia","REGION_ID":"16c0b06a-ca43-471e-9b89-b4abf3db8227"},{"GEO_ID":193,"ISO3":"SDN","NAME":"Sudan","REGION_ID":"51c6bdb0-3ae5-46fc-a151-3578816c8771"},{"GEO_ID":194,"ISO3":"SEN","NAME":"Senegal","REGION_ID":"ae5557b5-5936-420b-845b-88d61b3ef489"},{"GEO_ID":195,"ISO3":"SGP","NAME":"Singapore","REGION_ID":"a5ed5449-35a1-47e2-bf5c-ec3fc63e108c"},{"GEO_ID":196,"ISO3":"SGS","NAME":"South Georgia and the South Sandwich Islands","REGION_ID":"96663a45-e3a9-40fa-80ff-81f95e78d206"},{"GEO_ID":197,"ISO3":"SHN","NAME":"Saint Helena","REGION_ID":"e576a169-053a-46e4-a0a1-487754cf8014"},{"GEO_ID":198,"ISO3":"SJM","NAME":"Svalbard and Jan Mayen","REGION_ID":"b67390a1-0120-4930-8eac-a45edcaf1507"},{"GEO_ID":199,"ISO3":"SLB","NAME":"Solomon Islands","REGION_ID":"0bb5dc7e-ad4a-44c9-b2b2-03c4a5264948"},{"GEO_ID":200,"ISO3":"SLE","NAME":"Sierra Leone","REGION_ID":"c506eda9-5d3e-43f2-b5d6-34f7f152952f"},{"GEO_ID":201,"ISO3":"SLV","NAME":"El Salvador","REGION_ID":"66778a3f-a00b-4d2e-b97c-7ee9be22e216"},{"GEO_ID":202,"ISO3":"SMR","NAME":"San Marino","REGION_ID":"dc4c5e0b-6900-42b0-9738-a4072d3bd112"},{"GEO_ID":203,"ISO3":"SOM","NAME":"Somalia","REGION_ID":"98d8ead3-0f43-41e5-891c-78b049b7d0fc"},{"GEO_ID":204,"ISO3":"SPM","NAME":"Saint Pierre and Miquelon","REGION_ID":"cb5c0600-60f2-4997-b2da-91701f0f2228"},{"GEO_ID":205,"ISO3":"SRB","NAME":"Serbia","REGION_ID":"c4196d60-c7eb-4616-8838-21dde119e388"},{"GEO_ID":206,"ISO3":"SSD","NAME":"South Sudan","REGION_ID":"3a70ba24-1544-4e46-bb43-62017ef1ae08"},{"GEO_ID":207,"ISO3":"STP","NAME":"São Tomé and Príncipe","REGION_ID":"65adc315-dfb5-45f2-8a44-a480fa6137f7"},{"GEO_ID":208,"ISO3":"SUR","NAME":"Suriname","REGION_ID":"c647b2f4-25fc-47ee-be74-58f76a3080b1"},{"GEO_ID":209,"ISO3":"SVK","NAME":"Slovakia","REGION_ID":"44885edd-14e0-414f-99e5-40a1383079ad"},{"GEO_ID":210,"ISO3":"SVN","NAME":"Slovenia","REGION_ID":"bdb4acba-2c0c-4f26-bfd9-8c9dde9f2c81"},{"GEO_ID":211,"ISO3":"SWE","NAME":"Sweden","REGION_ID":"1968dda2-b750-445d-9bb3-7aab12906c84"},{"GEO_ID":212,"ISO3":"SWZ","NAME":"Swaziland","REGION_ID":"618e02db-743e-4b1b-81fa-85474d5e2ccd"},{"GEO_ID":213,"ISO3":"SXM","NAME":"Sint Maarten","REGION_ID":"5a574ec1-9797-4876-b0db-769a3871ad74"},{"GEO_ID":214,"ISO3":"SYC","NAME":"Seychelles","REGION_ID":"02adb491-b63a-47f3-8b3a-f8d2ee05f28a"},{"GEO_ID":215,"ISO3":"SYR","NAME":"Syria","REGION_ID":"73c61f2f-b0b4-4a05-8dbc-e1b4ade722ff"},{"GEO_ID":216,"ISO3":"TCA","NAME":"Turks and Caicos Islands","REGION_ID":"9a97a370-4bc5-4f7e-a0f3-e9f5fa2696ce"},{"GEO_ID":217,"ISO3":"TCD","NAME":"Chad","REGION_ID":"fe58733a-57fd-4b15-b0bd-99c3b4d0ec0b"},{"GEO_ID":218,"ISO3":"TGO","NAME":"Togo","REGION_ID":"d4b3d957-e92c-4bf4-bd41-6dac22c529c5"},{"GEO_ID":219,"ISO3":"THA","NAME":"Thailand","REGION_ID":"8d16c6bd-851a-45cd-8e4a-05147dbd2c08"},{"GEO_ID":220,"ISO3":"TJK","NAME":"Tajikistan","REGION_ID":"e027565b-3195-409b-b08f-d0db45438bf0"},{"GEO_ID":221,"ISO3":"TKL","NAME":"Tokelau","REGION_ID":"4c67906c-4156-4a35-8916-80495b0af7fd"},{"GEO_ID":222,"ISO3":"TKM","NAME":"Turkmenistan","REGION_ID":"3c1135ab-07bc-4d63-9a34-951c7091ccf6"},{"GEO_ID":223,"ISO3":"TLS","NAME":"Timor-Leste","REGION_ID":"442096e1-3ca8-4ab0-b2f8-8341c31ede27"},{"GEO_ID":224,"ISO3":"TON","NAME":"Tonga","REGION_ID":"654784dc-403f-4959-a05c-40c0ed0ec6f8"},{"GEO_ID":225,"ISO3":"TTO","NAME":"Trinidad and Tobago","REGION_ID":"69470e73-9179-40ac-a9b9-568fc0a7c327"},{"GEO_ID":226,"ISO3":"TUN","NAME":"Tunisia","REGION_ID":"24a497ce-fd07-4be2-b8c7-9eb5609c2fb6"},{"GEO_ID":227,"ISO3":"TUR","NAME":"Turkey","REGION_ID":"a95e0b9a-d8ba-4b8e-af33-3362f5b5e749"},{"GEO_ID":228,"ISO3":"TUV","NAME":"Tuvalu","REGION_ID":"26565c93-f604-4519-ba5b-e8addc96dcaa"},{"GEO_ID":229,"ISO3":"TWN","NAME":"Taiwan","REGION_ID":"0d81db60-be14-4380-b5b7-575f0aeeb892"},{"GEO_ID":230,"ISO3":"TZA","NAME":"Tanzania","REGION_ID":"c9725d3a-f95d-4c06-8c0a-2e451376f5ba"},{"GEO_ID":231,"ISO3":"UGA","NAME":"Uganda","REGION_ID":"4f78f663-3c54-4bf8-aea2-883efff761bb"},{"GEO_ID":232,"ISO3":"UKR","NAME":"Ukraine","REGION_ID":"ad54efce-e9c5-4e62-8535-189c1b9efc8a"},{"GEO_ID":233,"ISO3":"UMI","NAME":"United States Minor Outlying Islands","REGION_ID":"56001e8a-32f4-4ede-88f0-2123150a1903"},{"GEO_ID":234,"ISO3":"URY","NAME":"Uruguay","REGION_ID":"41a9e7e5-fa4e-4284-84fd-06452e0e08b4"},{"GEO_ID":235,"ISO3":"USA","NAME":"United States","REGION_ID":"0ac8d80c-ec74-490d-8e7d-5742400b035e"},{"GEO_ID":236,"ISO3":"UZB","NAME":"Uzbekistan","REGION_ID":"6df440da-5f21-4836-9844-d5fc34aa9b02"},{"GEO_ID":237,"ISO3":"VAT","NAME":"Vatican City","REGION_ID":"6a657615-04e7-4dcc-9cb4-1a139090cd7a"},{"GEO_ID":238,"ISO3":"VCT","NAME":"Saint Vincent and the Grenadines","REGION_ID":"9f2aff88-7b07-458d-a492-b8200e0c2097"},{"GEO_ID":239,"ISO3":"VEN","NAME":"Venezuela","REGION_ID":"3ae8db96-5654-4a7b-b21c-10df34e56812"},{"GEO_ID":240,"ISO3":"VGB","NAME":"British Virgin Islands","REGION_ID":"f94c07f3-3314-4328-9696-9aee46e482fe"},{"GEO_ID":241,"ISO3":"VIR","NAME":"Virgin Islands, U.S.","REGION_ID":"a5d68447-5daf-4966-8ade-0932f0bf17af"},{"GEO_ID":242,"ISO3":"VNM","NAME":"Vietnam","REGION_ID":"9142f2db-04de-4d79-87a2-09853627e851"},{"GEO_ID":243,"ISO3":"VUT","NAME":"Vanuatu","REGION_ID":"6cb772fa-28f8-43eb-9a2f-dcc3197b2ffa"},{"GEO_ID":244,"ISO3":"WLF","NAME":"Wallis and Futuna","REGION_ID":"6098e39f-c718-4fa1-91bb-77cf725c0e24"},{"GEO_ID":245,"ISO3":"WSM","NAME":"Samoa","REGION_ID":"2f5529ec-b481-437a-8d9f-aeb53b4f74ea"},{"GEO_ID":246,"ISO3":"XAD","NAME":"Akrotiri and Dhekelia","REGION_ID":"14030021-4de5-48bc-894c-409ec3c1e32d"},{"GEO_ID":247,"ISO3":"XCA","NAME":"Caspian Sea","REGION_ID":"be0dde06-0299-4936-bfdb-3961d200eb91"},{"GEO_ID":248,"ISO3":"XCL","NAME":"Clipperton Island","REGION_ID":"3f2070c4-045f-4017-a804-4688d8005464"},{"GEO_ID":249,"ISO3":"XKO","NAME":"Kosovo","REGION_ID":"7aadbf26-e559-4f19-9f55-8a78a7eb15cf"},{"GEO_ID":250,"ISO3":"XNC","NAME":"Northern Cyprus","REGION_ID":"b09ec9d4-c1fd-4779-b550-0aa3780430b7"},{"GEO_ID":251,"ISO3":"XPI","NAME":"Paracel Islands","REGION_ID":"66d94ead-934f-460a-8832-4b57b8f7ec1c"},{"GEO_ID":252,"ISO3":"XSP","NAME":"Spratly Islands","REGION_ID":"1ed51369-3119-4834-8f18-4eb6f0dc86fb"},{"GEO_ID":253,"ISO3":"YEM","NAME":"Yemen","REGION_ID":"9023dbfd-918b-4c07-a8e3-bd98c2bf8546"},{"GEO_ID":254,"ISO3":"ZAF","NAME":"South Africa","REGION_ID":"0c36c8f0-53f7-46d8-993c-6adb4bcee5e7"},{"GEO_ID":255,"ISO3":"ZMB","NAME":"Zambia","REGION_ID":"deddc8f1-7ff6-4c53-a4cb-de3c4bcfccc1"},{"GEO_ID":256,"ISO3":"ZWE","NAME":"Zimbabwe","REGION_ID":"2dfa435e-7455-4381-9ac5-c11739ac3053"}] From 8bfb765df2fab851623012475a3aa9519125aeba Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 19 Aug 2024 17:17:44 -0400 Subject: [PATCH 046/350] added icons and data to habitat table --- src/assets/icons/arrow-down-solid.svg | 1 + src/assets/icons/arrow-up-solid.svg | 1 + src/assets/icons/minus-solid.svg | 1 + .../biodiversity-indicators-component.jsx | 9 +- .../habitat-component-styles.module.scss | 22 ++-- .../habitat/habitat-component.jsx | 114 ++++++++++++------ .../dashboard-sidebar-component.jsx | 2 +- 7 files changed, 106 insertions(+), 44 deletions(-) create mode 100644 src/assets/icons/arrow-down-solid.svg create mode 100644 src/assets/icons/arrow-up-solid.svg create mode 100644 src/assets/icons/minus-solid.svg diff --git a/src/assets/icons/arrow-down-solid.svg b/src/assets/icons/arrow-down-solid.svg new file mode 100644 index 000000000..2c96bb5e7 --- /dev/null +++ b/src/assets/icons/arrow-down-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/arrow-up-solid.svg b/src/assets/icons/arrow-up-solid.svg new file mode 100644 index 000000000..7422915c3 --- /dev/null +++ b/src/assets/icons/arrow-up-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/minus-solid.svg b/src/assets/icons/minus-solid.svg new file mode 100644 index 000000000..fe94d5749 --- /dev/null +++ b/src/assets/icons/minus-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx index 0edaaab1f..46a22391d 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx @@ -67,11 +67,18 @@ function BioDiversityComponent(props) { const tableData = []; Object.keys(dataByCountry).forEach(country => { + const habitatCountry = dataByCountry[countryName]; + + // const countrySHS = country?.shs; + const startYearValue = habitatCountry?.frag[0].gisfrag; + // eslint-disable-next-line no-unsafe-optional-chaining + const lastCountryYearValue = habitatCountry?.shs.length - 1; const countryData = dataByCountry[country]; const global2001 = dataByCountry.Global?.shs[0]?.val || 0; const country2001 = roundUpNumber(countryData.shs[0]?.val || 0); const stewardship = (country2001 / global2001) * 100; - const { countryAreaScore, countryConnectivityScore } = getCountryScores(countryData); + + const { countryAreaScore, countryConnectivityScore } = getCountryScores(countryData, lastCountryYearValue, startYearValue); const shs = ((countryAreaScore + countryConnectivityScore) / 2) * 100; if (!Number.isNaN(shs)) { diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component-styles.module.scss index be5ff7e75..42656cee2 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component-styles.module.scss @@ -11,6 +11,10 @@ --border-color-hover: #{$brand-color-main-hover}; --small-font: 14px; + display: flex; + flex-direction: column; + gap: 0.75rem; + &.light{ --font-color: #{$black}; --border-color: #{$mol-blue}; @@ -29,15 +33,15 @@ align-items: flex-start; .material-symbols-outlined { - font-size: 48px; - color: #ffff33; + width: 32px; + fill: #ffff33; &.arrow_downward { - color: #c72929; + fill: #c72929; } &.arrow_upward { - color: #228d19; + fill: #228d19; } } @@ -53,6 +57,7 @@ .score { display: flex; + gap: 0.5rem; .results { display: flex; @@ -86,14 +91,14 @@ .chart { display: flex; flex-direction: column; - gap: 0.5rem; + gap: 0.75rem; align-items: center; .compareWrap{ display: flex; align-items: center; width: 75%; - gap: 0.5rem; + gap: 0.75rem; .compare { color: var(--font-color); @@ -172,11 +177,10 @@ .dataTable { border-collapse: collapse; - width: 90%; + width: 100%; th, td { - color: var(--save-button-text); font-family: STIX Two Text; font-size: var(--small-font); font-style: normal; @@ -202,6 +206,7 @@ th { vertical-align: bottom; + color: var(--font-color); } tbody { @@ -236,6 +241,7 @@ } td { + color: var(--save-button-text); padding: 0 5px; } } diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx index c3e61b210..9d7404b3f 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx @@ -13,6 +13,9 @@ import { CategoryScale, } from 'chart.js'; import { LightModeContext } from '../../../../../context/light-mode'; +import ArrowUpward from 'icons/arrow-up-solid.svg?react'; +import ArrowDownward from 'icons/arrow-down-solid.svg?react'; +import Stable from 'icons/minus-solid.svg?react'; ChartJS.register(LinearScale, LineElement, PointElement, Tooltip, Legend, CategoryScale); @@ -23,36 +26,16 @@ function HabitatComponent(props) { const [selectedCountry, setSelectedCountry] = useState('Global'); const [shiCountries, setShiCountries] = useState([]); const [chartData, setChartData] = useState(); + const [globalTrend, setGlobalTrend] = useState(''); + const [countryTrend, setCountryTrend] = useState(''); + const [globalTrendIcon, setGlobalTrendIcon] = useState(); + const [countryTrendIcon, setCountryTrendIcon] = useState(); - const onCountryChange = (event) => { - setSelectedCountry(event.currentTarget.value); - getChartData(event.currentTarget.value); - } - - useEffect(() => { - if (habitatTableData.length) { - const countries = habitatTableData.map(item => item.country); - - const sortedCountries = countries.sort((a, b) => { - const nameA = a.toUpperCase(); - const nameB = b.toUpperCase(); - if (nameA === 'GLOBAL' || nameB === 'GLOBAL') { - return -2; - } - if (nameA < nameB) { - return -1; - } - if (nameA > nameB) { - return 1; - } - return 0; - }); - - setShiCountries(sortedCountries); - - getChartData('Global'); - } - }, [habitatTableData]); + const TRENDS = { + UPWARD: 'arrow_upward', + DOWNWARD: 'arrow_downward', + STABLE: '', + }; const options = { plugins: { @@ -97,6 +80,39 @@ function HabitatComponent(props) { }, }; + useEffect(() => { + if (habitatTableData.length) { + const countries = habitatTableData.map(item => item.country); + + const sortedCountries = countries.sort((a, b) => { + const nameA = a.toUpperCase(); + const nameB = b.toUpperCase(); + if (nameA === 'GLOBAL' || nameB === 'GLOBAL') { + return -2; + } + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; + }); + + setShiCountries(sortedCountries); + + getChartData('Global'); + + setTrendArrows(); + } + }, [habitatTableData]); + + + const onCountryChange = (event) => { + setSelectedCountry(event.currentTarget.value); + getChartData(event.currentTarget.value); + } + const getChartData = (countrySelected) => { const dates = []; const currentCountry = dataByCountry[countryName]; @@ -219,6 +235,36 @@ function HabitatComponent(props) { getChartData(country.value); } + const setTrendArrows = () => { + const hs = habitatScore; + const gs = globalHabitatScore; + + if (hs < 100) { + setCountryTrend(TRENDS.DOWNWARD); + setCountryTrendIcon(); + } else if (hs > 100) { + setCountryTrend(TRENDS.UPWARD); + setCountryTrendIcon(); + } else { + setCountryTrend(TRENDS.STABLE); + setCountryTrendIcon(); + } + + if (gs < 100) { + setGlobalTrend(TRENDS.DOWNWARD); + setGlobalTrendIcon(); + } else if (gs > 100) { + setGlobalTrend(TRENDS.DOWNWARD); + setGlobalTrendIcon(); + } else { + setGlobalTrend(TRENDS.DOWNWARD); + setGlobalTrendIcon(); + } + + // this.countryHabitatScoreTitle = this.translate.instant('habitat_change', { change: this.countryHabitatChange, country: this.country, year: 2001 }); + // this.globalHabitatScoreTitle = this.translate.instant('habitat_global_change', { change: this.globalHabitatChange, year: 2001 }); + } + return (
@@ -230,8 +276,8 @@ function HabitatComponent(props) {
- - Down + + {countryTrendIcon}
{habitatScore}% @@ -242,11 +288,11 @@ function HabitatComponent(props) {
- - Up + + {globalTrendIcon}
- {(globalHabitatScore - 100).toFixed(2)}% + {(globalHabitatScore).toFixed(2)}% Suitable habitat lost globally since 2001
diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 85e35218e..fb86d7a9f 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -44,7 +44,7 @@ function DashboardSidebar(props) {
{isLoading && } diff --git a/src/containers/sidebars/dashboard-trends-sidebar/sii/sii-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/sii/sii-component.jsx index 7540d88eb..55654f5eb 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/sii/sii-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/sii/sii-component.jsx @@ -6,7 +6,7 @@ function SiiComponent(props) { return ( <> - + {/* */} ) } From 7bf0a8740d74d5cde86d0e733969112030c0ecbf Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 26 Sep 2024 13:15:39 -0400 Subject: [PATCH 126/350] remove partner logos --- .../dashboard-home/dashboard-home-component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx index 98e4330a2..d7c25d5b0 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx @@ -124,7 +124,7 @@ function DashboardHomeComponent(props) {
- + {/* */}
) } From f064bd4a9c56786cf55741be6ffdbdc49cedcec2 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 26 Sep 2024 13:53:57 -0400 Subject: [PATCH 127/350] added a layer and convert language --- .../species-info/species-info-component.jsx | 6 +++-- .../dashboard-trends-sidebar/index.js | 26 +++++++++---------- src/pages/dashboard/dashboard-selectors.js | 2 +- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx index ef71915b5..a6cd2d8e6 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx @@ -10,7 +10,9 @@ function SpeciesInfoComponent(props) { const { lightMode } = useContext(LightModeContext); useEffect(() => { if (speciesInfo) { - setTaxaImage(`https://mol.org/static/img/groups/taxa_${speciesInfo?.taxa}.png`); + if (speciesInfo?.taxa !== 'animals') { + setTaxaImage(`https://mol.org/static/img/groups/taxa_${speciesInfo?.taxa}.png`); + } } }, [speciesInfo]); @@ -22,7 +24,7 @@ function SpeciesInfoComponent(props) {
{speciesInfo?.commonname} {speciesInfo?.scientificname} - {speciesInfo?.taxa && taxa} + {taxaImage && taxa}

diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js index 23d637c70..1d69fdb0c 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/index.js +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -7,7 +7,7 @@ import mapStateToProps from './selectors'; import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; function DashboardTrendsSidebarContainer(props) { - const { countryISO, view } = props; + const { countryISO, view, map } = props; const [geo, setGeo] = useState(null); const [countryData, setCountryData] = useState(null); @@ -92,18 +92,18 @@ function DashboardTrendsSidebarContainer(props) { }, [view, countryISO]); //SPI layer - // useEffect(() => { - // EsriFeatureService.getFeatures({ - // url, - // whereClause: `GID_0 = '${countryISO}'`, - // returnGeometry: true, - // }).then((features) => { - // if (map) { - // const { layer } = features[0]; - // map.add(layer); - // } - // }); - // }, [map, view]); + useEffect(() => { + EsriFeatureService.getFeatures({ + url, + whereClause: `GID_0 = '${countryISO}'`, + returnGeometry: true, + }).then((features) => { + if (map) { + const { layer } = features[0]; + map.add(layer); + } + }); + }, [map, view]); return ( Date: Thu, 26 Sep 2024 14:41:14 -0400 Subject: [PATCH 128/350] update labels --- .../data-layers/data-layers-component.jsx | 8 ++++---- .../data-layers/grouped-list/grouped-list-component.jsx | 2 +- .../province-chart/province-chart-component.jsx | 5 +++-- .../province-chart/province-chart-styles.module.scss | 2 +- src/pages/dashboard/index.js | 3 ++- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 0a29d206c..bde2a902d 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -21,7 +21,7 @@ function DataLayerComponent(props) { const [dataLayers, setDataLayers] = useState({}); const [dataPoints, setDataPoints] = useState(); const [privateDataPoints, setPrivateDataPoints] = useState({ - 'Point Observations': { + 'Observations ponctuelles': { items: [], total_no_rows: 0, isActive: false, @@ -29,19 +29,19 @@ function DataLayerComponent(props) { } }); const [regionsData, setRegionsData] = useState({ - 'Protected Areas': { + 'Aires protégées': { items: [], total_no_rows: 0, isActive: false, showChildren: false, }, - 'Proposed Protection': { + 'Protection proposée': { items: [], total_no_rows: 0, isActive: false, showChildren: false, }, - 'Administrative Layers': { + 'Couches administratives': { items: [], total_no_rows: 0, isActive: false, diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx index c85a35ed1..8d636dcc5 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx @@ -61,7 +61,7 @@ function GroupedListComponent(props) { }; const findLayerToShow = (item) => { - if (item.type_title.toUpperCase() === 'POINT OBSERVATIONS') { + if (item.type_title.toUpperCase() === 'OBSERVATIONS PONCTUELLES') { const jsonLayer = EsriFeatureService.getGeoJsonLayer(speciesInfo.scientificname.replace(' ', '_')); map.add(jsonLayer); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index 713485b9c..1f10b7687 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -106,7 +106,7 @@ function ProvinceChartComponent(props) { const [sortedByArea, setSortedByArea] = useState(); const [sortedBySpecies, setSortedBySpecies] = useState(); const [isLoading, setIsLoading] = useState(true); - const [foundIndex, setFoundIndex] = useState(-1); + const [foundIndex, setFoundIndex] = useState(0); useEffect(() => { if (!spiData.trendData.length) return; @@ -200,7 +200,8 @@ function ProvinceChartComponent(props) { if (selectedProvince) { setFoundIndex(prov.findIndex(prov => prov.value === selectedProvince.region_name)); } else { - setFoundIndex(-1); + setFoundIndex(0); + getProvinceScores(prov[0]); } const spiSorted = sortProvincesBySPI(); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-styles.module.scss b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-styles.module.scss index bf7a13f96..bf838a65b 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-styles.module.scss +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-styles.module.scss @@ -31,7 +31,7 @@ span{ color: var(--font-color); font-family: "Open Sans"; - font-size: 13px; + font-size: 12px; font-style: italic; font-weight: 400; line-height: normal; diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index cbd3bcfd4..000ba5e3e 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -100,7 +100,8 @@ function DashboardContainer(props) { const getDataLayersData = async () => { const dataLayerParams = { scientificname: speciesName, - group: 'movement' + group: 'movement', + lang: 'fr', }; const dparams = new URLSearchParams(dataLayerParams); const dataLayersURL = `https://dev-api.mol.org/2.x/species/datasets?${dparams}`; From 3a5642b32dcfc8f4244e648cb9f3a3ef9dff9521 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 26 Sep 2024 15:57:06 -0400 Subject: [PATCH 129/350] layers and default values --- .../data-layers/data-layers-component.jsx | 6 ++-- .../dashboard-trends-sidebar/index.js | 27 ++++++++++-------- .../province-chart-component.jsx | 28 +++++++++++-------- src/services/esri-feature-service.ts | 8 ++++++ 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index bde2a902d..feacee348 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -138,7 +138,7 @@ function DataLayerComponent(props) { type="button" onClick={() => { }} > - {t('Species Data: Public')} + {t('DONNÉES SUR LES ESPÈCES: PUBLIC')} {!isLoading && dataPoints && { }} > - {t('Species Data: Private')} + {t('DONNÉES SUR L\'ESPÈCE: PRIVÉE')} { }} > - {t('Regions Data')} + {t('DONNÉES DES RÉGIONS')} { const year = '2021'; @@ -92,17 +92,22 @@ function DashboardTrendsSidebarContainer(props) { }, [view, countryISO]); //SPI layer + // useEffect(() => { + // EsriFeatureService.getFeatures({ + // url, + // whereClause: `GID_0 = '${countryISO}'`, + // returnGeometry: true, + // }).then((features) => { + // if (map) { + // const { layer } = features[0]; + // map.add(layer); + // } + // }); + // }, [map, view]); + useEffect(() => { - EsriFeatureService.getFeatures({ - url, - whereClause: `GID_0 = '${countryISO}'`, - returnGeometry: true, - }).then((features) => { - if (map) { - const { layer } = features[0]; - map.add(layer); - } - }); + const layer = EsriFeatureService.getVectorTileLayer(url); + map.add(layer); }, [map, view]); return ( diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index 1f10b7687..051808fb3 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -104,9 +104,10 @@ function ProvinceChartComponent(props) { const [selectedRegionScores, setSelectedRegionScores] = useState(); const [sortedBySpi, setSortedBySpi] = useState(); const [sortedByArea, setSortedByArea] = useState(); - const [sortedBySpecies, setSortedBySpecies] = useState(); + const [sortedBySpecies, setSortedBySpecies] = useState([]); const [isLoading, setIsLoading] = useState(true); const [foundIndex, setFoundIndex] = useState(0); + const [allSorted, setAllSorted] = useState(false); useEffect(() => { if (!spiData.trendData.length) return; @@ -146,14 +147,21 @@ function ProvinceChartComponent(props) { useEffect(() => { if (!countryRegions.length) return; getProvinces(); - }, [countryRegions]); + useEffect(() => { + if (allSorted && provinces.length && !selectedProvince) { + setFoundIndex(0); + getProvinceScores({ value: provinces[0].value }); + } + }, [allSorted, provinces]); + useEffect(() => { if (sortedBySpecies?.length && selectedProvince) { - getProvinceScores({ value: selectedProvince.region_name }) + getProvinceScores({ value: selectedProvince.region_name }); + setFoundIndex(provinces.findIndex(prov => prov.value === selectedProvince.region_name)); } - }, [sortedBySpecies]) + }, [sortedBySpecies]); const getChartData = () => { const { regions } = spiData.trendData[0]; @@ -197,19 +205,14 @@ function ProvinceChartComponent(props) { setProvinces(sortProvinces); - if (selectedProvince) { - setFoundIndex(prov.findIndex(prov => prov.value === selectedProvince.region_name)); - } else { - setFoundIndex(0); - getProvinceScores(prov[0]); - } - const spiSorted = sortProvincesBySPI(); setSortedBySpi(spiSorted); const areaSorted = sortProvincesByArea(); setSortedByArea(areaSorted); const speciesSorted = sortProvincesBySpecies(); setSortedBySpecies(speciesSorted); + + setAllSorted(true); } const getProvinceScores = (province) => { @@ -220,6 +223,9 @@ function ProvinceChartComponent(props) { setAreaRank(sortedByArea.findIndex(prov => prov.region_name === province.value) + 1); setSpeciesRank(sortedBySpecies.findIndex(prov => prov.region_name === province.value) + 1); setSelectedRegionScores(scores); + if (selectedProvince) { + setFoundIndex(provinces.findIndex(region => region.region_name === province.value)); + } setCountryProtected(scores.percentprotected_all); setCountrySPI(scores.spi_all); setCurrentYear(scores.year); diff --git a/src/services/esri-feature-service.ts b/src/services/esri-feature-service.ts index 9177cfeb6..4b6dc2762 100644 --- a/src/services/esri-feature-service.ts +++ b/src/services/esri-feature-service.ts @@ -4,6 +4,7 @@ import { AddFeature, GetFeatures, GetLayer } from 'types/services-types'; import FeatureLayer from '@arcgis/core/layers/FeatureLayer'; import GeoJSONLayer from '@arcgis/core/layers/GeoJSONLayer'; +import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer'; import WebTileLayer from '@arcgis/core/layers/WebTileLayer'; import { addFeatures, applyEdits, IQueryFeaturesResponse, queryFeatures @@ -42,6 +43,12 @@ function getFeatures({ }); } +function getVectorTileLayer(url){ + return new VectorTileLayer({ + url, + }); +} + function getGeoJsonLayer(scientificname){ return new GeoJSONLayer({ url: `https://storage.googleapis.com/cdn.mol.org/eow_demo/occ/${scientificname}.geojson` @@ -101,5 +108,6 @@ export default { getLayer, addFeature, getGeoJsonLayer, + getVectorTileLayer, getXYZLayer, }; From 3da053365000a7498f0e3f1d2a76214621490a55 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Thu, 26 Sep 2024 17:25:34 -0400 Subject: [PATCH 130/350] translated hc labels --- src/components/map-view/index.js | 135 +++++++----------- .../top-menu/top-menu-component.jsx | 4 +- .../dashboard-home-component.jsx | 2 +- .../dashboard-sidebar-component.jsx | 23 +-- .../grouped-list/grouped-list-component.jsx | 14 +- .../regions-analysis-component.jsx | 14 +- .../species-info/species-info-component.jsx | 2 +- .../dashboard-trends-sidebar-component.jsx | 2 +- .../score-distributions-shi-component.jsx | 3 +- .../temporal-trends-shi-component.jsx | 6 +- .../temporal-trends-sii-component.jsx | 4 +- .../score-distributions-spi-component.jsx | 9 +- .../temporal-trends-spi-component.jsx | 6 +- src/pages/dashboard/dashboard-selectors.js | 2 +- src/pages/dashboard/index.js | 1 - src/services/esri-feature-service.ts | 1 - 16 files changed, 105 insertions(+), 123 deletions(-) diff --git a/src/components/map-view/index.js b/src/components/map-view/index.js index de99d7418..769707634 100644 --- a/src/components/map-view/index.js +++ b/src/components/map-view/index.js @@ -10,7 +10,6 @@ import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer'; import TileLayer from '@arcgis/core/layers/TileLayer'; import GroupLayer from '@arcgis/core/layers/GroupLayer'; - import Component from './component'; import mapStateToProps from './selectors'; @@ -71,92 +70,62 @@ function ViewContainer(props) { }; useEffect(() => { - // loadModules( - // [ - // 'esri/Map', - // 'esri/layers/FeatureLayer', - // 'esri/layers/GraphicsLayer', - // 'esri/layers/GroupLayer', - // 'esri/layers/TileLayer', - // ], - // loaderOptions - // ) - // .then(([Map, FeatureLayer, GraphicsLayer, GroupLayer, TileLayer]) => { - const countries = new FeatureLayer({ - portalItem: { - id: '53a1e68de7e4499cad77c80daba46a94', - }, - }); - setCountryLayer(countries); - - const graphics = new GraphicsLayer({ - blendMode: 'destination-in', - title: 'layer', - }); - setGraphicsLayer(graphics); - - const tileLayer = new TileLayer({ - portalItem: { - // bottom layer in the group layer - id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery - }, - }); - - const group = new GroupLayer({ - layers: [ - tileLayer, - // world imagery layer will show where it overlaps with the graphicslayer - graphics, - ], - opacity: 0, // initially this layer will be transparent - }); - setGroupLayer(group); - - const flatMap = new Map({ - basemap: SATELLITE_BASEMAP_LAYER, - ground: { - surfaceColor: '#070710', - }, - layers: [countries, group], - }); - - setMap(flatMap); - - if (onMapLoad) { - onMapLoad(flatMap); - } - // }) - // .catch((err) => { - // console.error(err); - // }); + const countries = new FeatureLayer({ + portalItem: { + id: '53a1e68de7e4499cad77c80daba46a94', + }, + }); + setCountryLayer(countries); + + const graphics = new GraphicsLayer({ + blendMode: 'destination-in', + title: 'layer', + }); + setGraphicsLayer(graphics); + + const tileLayer = new TileLayer({ + portalItem: { + // bottom layer in the group layer + id: '10df2279f9684e4a9f6a7f08febac2a9', // world imagery + }, + }); + + const group = new GroupLayer({ + layers: [ + tileLayer, + // world imagery layer will show where it overlaps with the graphicslayer + graphics, + ], + opacity: 0, // initially this layer will be transparent + }); + setGroupLayer(group); + + const flatMap = new Map({ + basemap: SATELLITE_BASEMAP_LAYER, + ground: { + surfaceColor: '#070710', + }, + layers: [countries, group], + }); + + setMap(flatMap); + + if (onMapLoad) { + onMapLoad(flatMap); + } }, []); useEffect(() => { if (map) { - // loadModules(['esri/views/MapView'], loaderOptions) - // .then(([MapView]) => { - const flatView = new MapView({ - map, - container: `map-container-${mapName || mapId}`, - zoom: 6, - popup: null, - ...viewSettings, - }); - - // flatView.on('click', async (event) => { - // const query = { - // geometry: flatView.toMap(event), - // returnGeometry: true, - // outFields: ['*'], - // }; - // await highlightCountry(query, query.geometry, flatView); - // }); - - setView(flatView); - // }) - // .catch((err) => { - // console.error(err); - // }); + const flatView = new MapView({ + map, + container: `map-container-${mapName || mapId}`, + zoom: 6, + popup: null, + ...viewSettings, + }); + + setView(flatView); } }, [map, viewSettings]); diff --git a/src/components/top-menu/top-menu-component.jsx b/src/components/top-menu/top-menu-component.jsx index 10ebaf29d..c94a3d4ad 100644 --- a/src/components/top-menu/top-menu-component.jsx +++ b/src/components/top-menu/top-menu-component.jsx @@ -6,9 +6,9 @@ function TopMenuComponent(props) { const t = useT(); return (

) } diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx index d7c25d5b0..695b1776b 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-home/dashboard-home-component.jsx @@ -91,7 +91,7 @@ function DashboardHomeComponent(props) { handleClick={() => setSelectedIndex(NAVIGATION.REGION)} />
- {t('Popular Species')} + {t('Espèces populaires')}
selectSpecies('Cossypha polioptera')} >
diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 6bf3a8e52..e24021c16 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -24,10 +24,10 @@ function DashboardSidebar(props) { const filterStart = [ { name: 'dataset', - title: 'Expected Sources', + title: 'Sources prévues', filters: [ { - name: 'Expert Range Map', + name: 'Carte de répartition des experts', active: false, test: species => species.datasetList.map(d => d.product_type).indexOf('range') > -1, count: 0, @@ -38,7 +38,7 @@ function DashboardSidebar(props) { }, { name: 'dataset', - title: 'Recorded Sources', + title: 'Sources enregistrées', filters: [ { name: 'Occurrence', @@ -49,7 +49,7 @@ function DashboardSidebar(props) { type: 'and', }, { - name: 'Local Inventory', + name: 'Inventaire local', active: false, test: species => species.datasetList.map(d => d.product_type).indexOf('localinv') > -1, @@ -61,10 +61,10 @@ function DashboardSidebar(props) { }, { name: 'threat', - title: 'IUCN Status', + title: 'IUCN Statut', filters: [ { - name: 'Critically Endangered', + name: 'En danger critique d\'extinction', active: false, test: species => species.traits?.threat_status_code === 'CR', count: 0, @@ -72,7 +72,7 @@ function DashboardSidebar(props) { type: 'or', }, { - name: 'Endangered', + name: 'En danger', result: false, active: false, test: species => species.traits?.threat_status_code === 'EN', @@ -80,7 +80,7 @@ function DashboardSidebar(props) { type: 'or', }, { - name: 'Vulnerable', + name: 'Vulnérable', active: false, test: species => species.traits?.threat_status_code === 'VU', count: 0, @@ -88,7 +88,7 @@ function DashboardSidebar(props) { result: false, }, { - name: 'Least Concern', + name: 'Préoccupation mineure', active: false, test: species => species.traits?.threat_status_code === 'LC', count: 0, @@ -96,7 +96,7 @@ function DashboardSidebar(props) { result: false, }, { - name: 'Unknown', + name: 'Inconnu', active: false, result: false, test: species => species.traits?.threat_status_code === undefined, @@ -132,7 +132,8 @@ function DashboardSidebar(props) { {!lightMode && } {lightMode && } -

{countryName}

+ {/*

{countryName}

*/} +

République démocratique du Congo

diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx index 8d636dcc5..03a3f812d 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx @@ -20,7 +20,10 @@ function GroupedListComponent(props) { showChildren: showChildren, } }); - } + }; + + const protectedAreasURL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/VectorTileServer'; + const vtLayer = EsriFeatureService.getVectorTileLayer(protectedAreasURL); // update value of all children const updateChildren = (item) => { @@ -58,11 +61,18 @@ function GroupedListComponent(props) { } }); } + + if (item.toUpperCase() === 'AIRES PROTÉGÉES') { + if (!dataPoints[item].isActive) { + map.add(vtLayer); + } else { + map.remove(vtLayer); + } + } }; const findLayerToShow = (item) => { if (item.type_title.toUpperCase() === 'OBSERVATIONS PONCTUELLES') { - const jsonLayer = EsriFeatureService.getGeoJsonLayer(speciesInfo.scientificname.replace(' ', '_')); map.add(jsonLayer); } diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx index 6f3d5a296..14ec4831e 100644 --- a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx @@ -5,6 +5,7 @@ import Radio from '@mui/material/Radio'; import RadioGroup from '@mui/material/RadioGroup'; import FormControlLabel from '@mui/material/FormControlLabel'; import SearchLocation from 'components/search-location'; +import EsriFeatureService from 'services/esri-feature-service'; import { SEARCH_TYPES } from 'constants/search-location-constants'; @@ -16,9 +17,17 @@ import { useT } from '@transifex/react'; function RegionsAnalysisComponent(props) { const t = useT(); - const { view, selectedOption } = props; + const { view, selectedOption, map } = props; const { lightMode } = useContext(LightModeContext); + const optionSelected = (event) => { + if (event.currentTarget.value === 'protectedAreas') { + const protectedAreasURL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/VectorTileServer'; + const vtLayer = EsriFeatureService.getVectorTileLayer(protectedAreasURL); + map.add(vtLayer); + } + } + return (
{t('Regions Analysis')} @@ -30,6 +39,7 @@ function RegionsAnalysisComponent(props) { } label={t('Protected Areas')} /> } label={t('Proposed Protected Areas')} /> @@ -51,7 +61,7 @@ function RegionsAnalysisComponent(props) {
diff --git a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx index a6cd2d8e6..2ff79e30c 100644 --- a/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/species-info/species-info-component.jsx @@ -10,7 +10,7 @@ function SpeciesInfoComponent(props) { const { lightMode } = useContext(LightModeContext); useEffect(() => { if (speciesInfo) { - if (speciesInfo?.taxa !== 'animals') { + if (speciesInfo?.taxa && speciesInfo?.taxa !== 'animals') { setTaxaImage(`https://mol.org/static/img/groups/taxa_${speciesInfo?.taxa}.png`); } } diff --git a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx index e91678b27..9347b5b2a 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx @@ -21,7 +21,7 @@ function DashboardTrendsSidebar(props) {
{t('Conservation Metrics')} - +
{!isLoading && dataPoints && { }} > - {t('DONNÉES SUR L\'ESPÈCE: PRIVÉE')} + {t('Species Data: Private')} { }} > - {t('DONNÉES DES RÉGIONS')} + {t('Regions Data')} { const showChildren = !dataPoints[key].showChildren; @@ -143,7 +145,7 @@ function GroupedListComponent(props) { /> (
  • findLayerToShow(item)}> } /> @@ -173,7 +175,7 @@ function GroupedListComponent(props) { } {dataPoints[key].items.length === 0 &&
    displaySingleLayer(key)}> } /> diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx index 14ec4831e..cf2116ed2 100644 --- a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx @@ -61,7 +61,7 @@ function RegionsAnalysisComponent(props) {
    diff --git a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx index 9347b5b2a..6053e7866 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx @@ -26,7 +26,7 @@ function DashboardTrendsSidebar(props) {
  • - {trendOption === 1 && } - {trendOption === 2 && } - {trendOption === 3 && } + {tabOption === 1 && } + {tabOption === 2 && } + {tabOption === 3 && }
    ); } diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js index cdb0266c0..dacce8b9c 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/index.js +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -20,6 +20,14 @@ function DashboardTrendsSidebarContainer(props) { const [spiData, setSpiData] = useState({trendData: [], scoresData: []}); const [siiData, setSiiData] = useState({trendData: [], scoresData: []}); + const [provinces, setProvinces] = useState([]); + const [sortedBySpi, setSortedBySpi] = useState(); + const [sortedByArea, setSortedByArea] = useState(); + const [sortedBySpecies, setSortedBySpecies] = useState([]); + const [allSorted, setAllSorted] = useState(false); + const [countryRegions, setCountryRegions] = useState([]); + const [selectedProvince, setSelectedProvince] = useState(); + const url = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; @@ -58,6 +66,8 @@ function DashboardTrendsSidebarContainer(props) { setShiValue(shi); const spiTD = spiTrendData; + const { regions } = spiTrendData[0]; + setCountryRegions(regions); const spiTrendsValues = spiTD[0].country_scores; const spi = (spiTrendsValues[spiTrendsValues.length - 1].spi_all).toFixed(2); setSpiValue(spi); @@ -74,6 +84,11 @@ function DashboardTrendsSidebarContainer(props) { getData(); }, []); + useEffect(() => { + if (!countryRegions?.length) return; + getProvinces(); + }, [countryRegions]); + // find and zoom to region useEffect(() => { EsriFeatureService.getFeatures({ @@ -101,6 +116,83 @@ function DashboardTrendsSidebarContainer(props) { } }, [map, view]); + const getProvinces = () => { + const prov = countryRegions.map(region => { + return { value: region.region_name, label: region.region_name } + }); + + const sortProvinces = prov.sort((a, b) => { + const nameA = a.label.toUpperCase(); + const nameB = b.label.toUpperCase(); + if (nameA < nameB) { + return -1; + } + if (nameA > nameB) { + return 1; + } + return 0; + }); + + setProvinces(sortProvinces); + + const spiSorted = sortProvincesBySPI(); + setSortedBySpi(spiSorted); + const areaSorted = sortProvincesByArea(); + setSortedByArea(areaSorted); + const speciesSorted = sortProvincesBySpecies(); + setSortedBySpecies(speciesSorted); + + setAllSorted(true); + } + + const sortProvincesBySPI = () => { + const sorted = [...countryRegions].sort((a, b) => { + const spi_A = a.regional_scores[a.regional_scores.length - 1].spi_all; + const spi_B = b.regional_scores[b.regional_scores.length - 1].spi_all; + if (spi_A > spi_B) { + return -1; + } + if (spi_A < spi_B) { + return 1; + } + return 0; + }); + + return sorted; + } + + const sortProvincesByArea = () => { + const sorted = [...countryRegions].sort((a, b) => { + const spi_A = a.regional_scores[a.regional_scores.length - 1].region_area; + const spi_B = b.regional_scores[b.regional_scores.length - 1].region_area; + if (spi_A > spi_B) { + return -1; + } + if (spi_A < spi_B) { + return 1; + } + return 0; + }); + + return sorted; + } + + const sortProvincesBySpecies = () => { + const sorted = [...countryRegions].sort((a, b) => { + const spi_A = a.regional_scores[a.regional_scores.length - 1].nspecies; + const spi_B = b.regional_scores[b.regional_scores.length - 1].nspecies; + if (spi_A > spi_B) { + return -1; + } + if (spi_A < spi_B) { + return 1; + } + return 0; + }); + + return sorted; + } + return ( ); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx index 16e4dd7b5..4fd4a1b5d 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx @@ -6,7 +6,6 @@ import TemporalTrendsSpiComponent from './temporal-trends/temporal-trends-spi-co function SpiComponent(props) { const [activeTrend, setActiveTrend] = useState(PROVINCE_TREND); - const [selectedProvince, setSelectedProvince] = useState(); const [year, setYear] = useState(); return ( @@ -14,14 +13,10 @@ function SpiComponent(props) { diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index 36c5dc4e0..32868c572 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -24,7 +24,18 @@ ChartJS.register(LinearScale, ArcElement, PointElement, Tooltip, Legend); function ProvinceChartComponent(props) { const t = useT(); const { lightMode } = useContext(LightModeContext); - const { spiData, setSelectedProvince, countryRegions, selectedProvince, clickedRegion } = props; + const { + spiData, + setSelectedProvince, + countryRegions, + selectedProvince, + clickedRegion, + sortedBySpi, + sortedByArea, + sortedBySpecies, + provinces, + allSorted } = props; + const blankData = { labels: [t('Global SPI'), t('Remaining')], datasets: [ @@ -92,7 +103,6 @@ function ProvinceChartComponent(props) { } }; - const [provinces, setProvinces] = useState([]); const [bubbleData, setBubbleData] = useState(); const [currentYear, setCurrentYear] = useState() const [spiArcData, setSpiArcData] = useState(blankData); @@ -102,23 +112,20 @@ function ProvinceChartComponent(props) { const [areaRank, setAreaRank] = useState(0); const [speciesRank, setSpeciesRank] = useState(0); const [selectedRegionScores, setSelectedRegionScores] = useState(); - const [sortedBySpi, setSortedBySpi] = useState(); - const [sortedByArea, setSortedByArea] = useState(); - const [sortedBySpecies, setSortedBySpecies] = useState([]); const [isLoading, setIsLoading] = useState(true); const [foundIndex, setFoundIndex] = useState(0); - const [allSorted, setAllSorted] = useState(false); useEffect(() => { if (!spiData.trendData.length) return; setIsLoading(false); - const { country_scores } = spiData.trendData[0]; - // setCountryRegions(regions); + const { country_scores } = spiData.trendData[0]; const { spi_all, percentprotected_all } = country_scores[country_scores.length - 1]; + setCountrySPI(spi_all); setCountryProtected(percentprotected_all); getChartData(); + const spi = { labels: [t('Global SPI'), t('Remaining')], datasets: [ @@ -144,11 +151,6 @@ function ProvinceChartComponent(props) { setSpiArcData(spi); }, [spiData.trendData]); - useEffect(() => { - if (!countryRegions.length) return; - getProvinces(); - }, [countryRegions]); - useEffect(() => { if (allSorted && provinces.length && !selectedProvince) { setFoundIndex(0); @@ -164,11 +166,11 @@ function ProvinceChartComponent(props) { }, [sortedBySpecies]); useEffect(() => { - if (!clickedRegion) return; - getProvinceScores({ value: clickedRegion.NAME_1 }); + if (clickedRegion) { + getProvinceScores({ value: clickedRegion.NAME_1 }); + } }, [clickedRegion]) - const getChartData = () => { const { regions } = spiData.trendData[0]; const data = []; @@ -192,46 +194,16 @@ function ProvinceChartComponent(props) { setBubbleData({ datasets: data }); } - const getProvinces = () => { - const prov = countryRegions.map(region => { - return { value: region.region_name, label: region.region_name } - }); - - const sortProvinces = prov.sort((a, b) => { - const nameA = a.label.toUpperCase(); - const nameB = b.label.toUpperCase(); - if (nameA < nameB) { - return -1; - } - if (nameA > nameB) { - return 1; - } - return 0; - }); - - setProvinces(sortProvinces); - - const spiSorted = sortProvincesBySPI(); - setSortedBySpi(spiSorted); - const areaSorted = sortProvincesByArea(); - setSortedByArea(areaSorted); - const speciesSorted = sortProvincesBySpecies(); - setSortedBySpecies(speciesSorted); - - setAllSorted(true); - } - const getProvinceScores = (province) => { const foundRegion = countryRegions.filter(region => region.region_name === province.value); const scores = foundRegion[0].regional_scores[foundRegion[0].regional_scores.length - 1]; + setSelectedProvince(foundRegion[0]); setSpiRank(sortedBySpi.findIndex(prov => prov.region_name === province.value) + 1); setAreaRank(sortedByArea.findIndex(prov => prov.region_name === province.value) + 1); setSpeciesRank(sortedBySpecies.findIndex(prov => prov.region_name === province.value) + 1); setSelectedRegionScores(scores); - if (selectedProvince) { - setFoundIndex(provinces.findIndex(region => region.value === province.value)); - } + setFoundIndex(provinces.findIndex(region => region.value === province.value)); setCountryProtected(scores.percentprotected_all); setCountrySPI(scores.spi_all); setCurrentYear(scores.year); @@ -261,54 +233,6 @@ function ProvinceChartComponent(props) { setSpiArcData(spi); } - const sortProvincesBySPI = () => { - const sorted = [...countryRegions].sort((a, b) => { - const spi_A = a.regional_scores[a.regional_scores.length - 1].spi_all; - const spi_B = b.regional_scores[b.regional_scores.length - 1].spi_all; - if (spi_A > spi_B) { - return -1; - } - if (spi_A < spi_B) { - return 1; - } - return 0; - }); - - return sorted; - } - - const sortProvincesByArea = () => { - const sorted = [...countryRegions].sort((a, b) => { - const spi_A = a.regional_scores[a.regional_scores.length - 1].region_area; - const spi_B = b.regional_scores[b.regional_scores.length - 1].region_area; - if (spi_A > spi_B) { - return -1; - } - if (spi_A < spi_B) { - return 1; - } - return 0; - }); - - return sorted; - } - - const sortProvincesBySpecies = () => { - const sorted = [...countryRegions].sort((a, b) => { - const spi_A = a.regional_scores[a.regional_scores.length - 1].nspecies; - const spi_B = b.regional_scores[b.regional_scores.length - 1].nspecies; - if (spi_A > spi_B) { - return -1; - } - if (spi_A < spi_B) { - return 1; - } - return 0; - }); - - return sorted; - } - const selectClickedRegion = (elements) => { const datasetIndex = elements[0].datasetIndex; const dataIndex = elements[0].index; diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/temporal-trends-spi-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/temporal-trends-spi-component.jsx index e680e9a11..456b0a566 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/temporal-trends-spi-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/temporal-trends-spi-component.jsx @@ -24,15 +24,12 @@ function TemporalTrendsSpiComponent(props) { const [showTable, setShowTable] = useState(false); const [spiInfo, setSpiInfo] = useState(); const [areaProtectedPercent, setAreaProtectedPercent] = useState(); - const [countryRegions, setCountryRegions] = useState([]); const [areaProtected, setAreaProtected] = useState(0); const [startYear, setStartYear] = useState('1980'); useEffect(() => { if (!spiData.trendData.length) return; getNationalData(); - const { regions } = spiData.trendData[0]; - setCountryRegions(regions); }, [spiData.trendData]); @@ -132,7 +129,6 @@ function TemporalTrendsSpiComponent(props) { )} {activeTrend === PROVINCE_TREND && } } { diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index 15d4fa407..79b9cd316 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -35,36 +35,48 @@ function DashboardViewComponent(props) { const [regionLayers, setRegionLayers] = useState({}); const [mapViewSettings, setMapViewSettings] = useState(viewSettings); const [clickedRegion, setClickedRegion] = useState(); + const [tabOption, setTabOption] = useState(2); useEffect(() => { if (geometry && view) { view.center = [geometry.longitude, geometry.latitude]; - view.on('click', async (event) => { - let hits; - try { - if (selectedIndex === NAVIGATION.TRENDS) { - hits = await hitTest(event); - - if (hits) { - console.log(hits); - setClickedRegion(hits); - } - } - } catch { } - }); - - view.on('pointer-move', async (event) => { - let hits; - try { - if (selectedIndex === NAVIGATION.TRENDS) { - hits = await hitTest(event); - } - } catch { } - }) + view.on('click', handleRegionClicked); + + view.on('pointer-move', handlePointerMove) } }, [view, geometry]); + useEffect(() => { + if (tabOption === 2) { + view?.on('click', handleRegionClicked) + } + }, [tabOption, view]) + + + const handleRegionClicked = async (event) => { + let hits; + try { + if (selectedIndex === NAVIGATION.TRENDS) { + hits = await hitTest(event); + + if (hits) { + console.log(hits); + setClickedRegion(hits); + } + } + } catch { } + } + + const handlePointerMove = async (event) => { + let hits; + try { + if (selectedIndex === NAVIGATION.TRENDS) { + hits = await hitTest(event); + } + } catch { } + } + const hitTest = promiseUtils.debounce(async (event) => { const response = await view.hitTest(event); if (response.results.length) { @@ -103,6 +115,8 @@ function DashboardViewComponent(props) { regionLayers={regionLayers} setRegionLayers={setRegionLayers} clickedRegion={clickedRegion} + tabOption={tabOption} + setTabOption={setTabOption} {...props} /> Date: Fri, 4 Oct 2024 16:11:41 -0400 Subject: [PATCH 142/350] regions map layer --- .../dashboard-trends-sidebar/index.js | 9 ++++- .../dashboard-trends-view-config.js | 4 +- .../dashboard-view-component.jsx | 39 +++++++++++++++---- src/services/esri-feature-service.ts | 18 +++++++++ 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js index dacce8b9c..656990ea8 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/index.js +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -29,7 +29,10 @@ function DashboardTrendsSidebarContainer(props) { const [selectedProvince, setSelectedProvince] = useState(); const url = - 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; + `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_provinces_spi_oct4/MapServer`; + + const featureLayerURL = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/FeatureServer`; + // 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; const getData = async () => { const year = '2021'; @@ -110,8 +113,10 @@ function DashboardTrendsSidebarContainer(props) { if(!map && !view) return; if(!regionLayers.hasOwnProperty('SPI REGIONS')) { - const layer = EsriFeatureService.getVectorTileLayer(url); + const layer = EsriFeatureService.getTileLayer(url); setRegionLayers({ ...regionLayers, ['SPI REGIONS']: layer }); + const featureLayer = EsriFeatureService.getFeatureLayer(featureLayerURL); + map.add(featureLayer); map.add(layer); } }, [map, view]); diff --git a/src/containers/views/dashboard-view/dashboard-trends-view-config.js b/src/containers/views/dashboard-view/dashboard-trends-view-config.js index b63e11e35..66484aee9 100644 --- a/src/containers/views/dashboard-view/dashboard-trends-view-config.js +++ b/src/containers/views/dashboard-view/dashboard-trends-view-config.js @@ -20,9 +20,9 @@ export default { { title: ADMIN_AREAS_FEATURE_LAYER }, ], highlightOptions:{ - color: [255, 255, 0, 1], // bright yellow + color: [22, 186, 180, 1], haloOpacity: 0.9, - fillOpacity: 0.2 + fillOpacity: 0.7 }, padding: { left: 200, diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index 79b9cd316..a9dc5db41 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -37,13 +37,16 @@ function DashboardViewComponent(props) { const [clickedRegion, setClickedRegion] = useState(); const [tabOption, setTabOption] = useState(2); + let highlight; + let hoverHighlight; + useEffect(() => { if (geometry && view) { view.center = [geometry.longitude, geometry.latitude]; view.on('click', handleRegionClicked); - view.on('pointer-move', handlePointerMove) + view.on('pointer-move', handlePointerMove); } }, [view, geometry]); @@ -58,11 +61,19 @@ function DashboardViewComponent(props) { let hits; try { if (selectedIndex === NAVIGATION.TRENDS) { + let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); hits = await hitTest(event); if (hits) { console.log(hits); - setClickedRegion(hits); + setClickedRegion(hits.attributes); + + if (highlight) { + highlight.remove(); + hoverHighlight.remove(); + } + + highlight = layerView.highlight(hits.graphic); } } } catch { } @@ -72,18 +83,32 @@ function DashboardViewComponent(props) { let hits; try { if (selectedIndex === NAVIGATION.TRENDS) { + let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); hits = await hitTest(event); + + if (hits) { + if (hoverHighlight) { + hoverHighlight.remove(); + } + + hoverHighlight = layerView.highlight(hits.graphic); + // console.log(hits.graphic); + } else { + if (hoverHighlight) { + hoverHighlight.remove(); + } + } } } catch { } } const hitTest = promiseUtils.debounce(async (event) => { - const response = await view.hitTest(event); - if (response.results.length) { - const graphic = response.results[0].graphic; - const attributes = graphic.attributes; + const { results } = await view.hitTest(event); + if (results.length) { + const { graphic } = results.find(x => x.graphic.attributes.OBJECTID); + const { attributes } = graphic; if (attributes.hasOwnProperty('region_name')) { - return attributes; + return { graphic, attributes } } else { return null; } diff --git a/src/services/esri-feature-service.ts b/src/services/esri-feature-service.ts index 91d7fed92..bcb7f67d7 100644 --- a/src/services/esri-feature-service.ts +++ b/src/services/esri-feature-service.ts @@ -4,6 +4,7 @@ import { AddFeature, GetFeatures, GetLayer } from 'types/services-types'; import FeatureLayer from '@arcgis/core/layers/FeatureLayer'; import GeoJSONLayer from '@arcgis/core/layers/GeoJSONLayer'; +import TileLayer from '@arcgis/core/layers/TileLayer'; import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer'; import WebTileLayer from '@arcgis/core/layers/WebTileLayer'; import { @@ -49,6 +50,13 @@ function getVectorTileLayer(url){ }); } +function getFeatureLayer(url){ + return new FeatureLayer({ + url, + outFields: ['*'], + }); +} + function getGeoJsonLayer(scientificname){ return new GeoJSONLayer({ url: `https://storage.googleapis.com/cdn.mol.org/eow_demo/occ/${scientificname}.geojson` @@ -64,6 +72,14 @@ async function getXYZLayer(scientificname){ }) } +function getTileLayer(url){ + return new TileLayer({ + url, + id: 'regions', + visible: true, + }); +} + function getLayer({ slug, outFields = ['*'] }: GetLayer) { return new FeatureLayer({ url: LAYERS_URLS[slug], @@ -109,7 +125,9 @@ export default { getFeatures, getLayer, addFeature, + getFeatureLayer, getGeoJsonLayer, getVectorTileLayer, getXYZLayer, + getTileLayer, }; From e26f74fae35973fdf3f927d00755441352460ad7 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Tue, 8 Oct 2024 09:48:21 -0400 Subject: [PATCH 143/350] highlight select region --- .../biodiversity-indicators-component.jsx | 1 + ...biodiversity-indicators-styles.module.scss | 6 ++++ .../habitat/habitat-component.jsx | 3 +- .../biodiversity-indicators/index.js | 3 ++ .../data-layers/data-layers-component.jsx | 12 ++++---- .../grouped-list/grouped-list-component.jsx | 15 +++++++++- .../sidebars/dashboard-sidebar/index.js | 4 ++- .../dashboard-trends-sidebar/index.js | 12 +++++--- .../province-chart-component.jsx | 25 ++++++++++++++-- .../dashboard-view-component.jsx | 29 ++++++++++--------- 10 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx index f265ff5c4..b5a170a3e 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-component.jsx @@ -69,6 +69,7 @@ function BioDiversityComponent(props) { })} onClick={() => setSelectedTab(3)} > + 0.00% {t('Information Score')}
    diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss index caf0310ea..abad2b4d4 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/biodiversity-indicators-styles.module.scss @@ -37,6 +37,7 @@ margin-top: 10px; padding-left: 26px; padding-right: 5px; + border-bottom: solid 2px var(--border-color); button{ display: flex; @@ -66,6 +67,11 @@ &.selected{ background-color: var(--border-color); + color: $white; + border: solid 2px var(--border-color); + border-top-right-radius: 8px; + border-top-left-radius: 8px; + border-bottom: none; label, span{ diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx index 3312f25d1..0e5212ac5 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/habitat/habitat-component.jsx @@ -33,7 +33,8 @@ function HabitatComponent(props) { countryTrendIcon, onCountryChange, chartOptions, - updateCountry } = props; + updateCountry, + startYear } = props; return (
    diff --git a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/index.js b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/index.js index 573e74c0e..3e4ba16e0 100644 --- a/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/index.js +++ b/src/containers/sidebars/dashboard-sidebar/biodiversity-indicators/index.js @@ -17,6 +17,7 @@ function BioDiversityContainer(props) { const [protectionTableData, setProtectionTableData] = useState([]); const [protectionArea, setProtectionArea] = useState('0'); const [globalProtectionArea, setGlobalProtectionArea] = useState('0'); + const [startYear, setStartYear] = useState(1950) // get habitat score information @@ -45,6 +46,7 @@ function BioDiversityContainer(props) { // TODO: handle no frag values const startYearValue = country?.frag[0]?.gisfrag ?? 0; + setStartYear(country?.frag[0]?.year ?? country?.shs[0]?.year ?? 2001); // eslint-disable-next-line no-unsafe-optional-chaining const lastCountryYearValue = country?.shs.length - 1; let globalAreaScore = 0; @@ -237,6 +239,7 @@ function BioDiversityContainer(props) { protectionTableData={protectionTableData} protectionArea={protectionArea} globalProtectionArea={globalProtectionArea} + startYear={startYear} {...props} />; } diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index 5eb4b76d4..8793021f6 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -35,12 +35,12 @@ function DataLayerComponent(props) { isActive: false, showChildren: false, }, - 'Proposed Protection': { - items: [], - total_no_rows: '', - isActive: false, - showChildren: false, - }, + // 'Proposed Protection': { + // items: [], + // total_no_rows: '', + // isActive: false, + // showChildren: false, + // }, 'Administrative Layers': { items: [], total_no_rows: '', diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx index 40f5dbfba..654b2ea08 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx @@ -27,6 +27,9 @@ function GroupedListComponent(props) { const protectedAreasURL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/VectorTileServer'; const vtLayer = EsriFeatureService.getVectorTileLayer(protectedAreasURL); + const administrativeLayerURL = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_provinces_spi_oct4/MapServer`; + const administrativeLayer = EsriFeatureService.getTileLayer(administrativeLayerURL); + // update value of all children const updateChildren = (item) => { const isActive = !dataPoints[item].isActive; @@ -68,7 +71,7 @@ function GroupedListComponent(props) { }); } - if (typeof item === 'string' && item.toUpperCase() === 'AIRES PROTÉGÉES') { + if (typeof item === 'string' && item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'PROTECTED AREAS') { if (!dataPoints[item].isActive) { setRegionLayers({ ...regionLayers, [item.toUpperCase()]: vtLayer }); map.add(vtLayer); @@ -78,6 +81,16 @@ function GroupedListComponent(props) { setRegionLayers(rest); map.remove(layer); } + } else if (typeof item === 'string' && item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'ADMINISTRATIVE LAYERS') { + if (!dataPoints[item].isActive) { + setRegionLayers({ ...regionLayers, [item.toUpperCase()]: administrativeLayer }); + map.add(administrativeLayer); + } else { + const layer = regionLayers[item.toUpperCase()]; + const { [item.toUpperCase()]: name, ...rest } = regionLayers; + setRegionLayers(rest); + map.remove(layer); + } } }; diff --git a/src/containers/sidebars/dashboard-sidebar/index.js b/src/containers/sidebars/dashboard-sidebar/index.js index d2500c032..e23bd784b 100644 --- a/src/containers/sidebars/dashboard-sidebar/index.js +++ b/src/containers/sidebars/dashboard-sidebar/index.js @@ -13,8 +13,10 @@ function DashboardSidebarContainer(props) { if(regionLayers.hasOwnProperty('SPI REGIONS') && selectedIndex !== NAVIGATION.TRENDS){ const layer = regionLayers['SPI REGIONS']; - const { ['SPI REGIONS']: name, ...rest } = regionLayers; + const featureLayer = regionLayers['SPI REGIONS FEATURE']; + const { ['SPI REGIONS']: name, ['SPI REGIONS FEATURE']: featureName, ...rest } = regionLayers; setRegionLayers(rest); + map.remove(featureLayer); map.remove(layer); } }, [map, view]); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js index 656990ea8..76b981362 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/index.js +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -1,13 +1,14 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import EsriFeatureService from 'services/esri-feature-service'; +import SearchVM from "@arcgis/core/widgets/Search/SearchViewModel.js"; import Component from './dashboard-trends-sidebar-component.jsx'; import mapStateToProps from './selectors'; import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; function DashboardTrendsSidebarContainer(props) { - const { countryISO, view, map, regionLayers, setRegionLayers } = props; + const { countryISO, view, map, regionLayers, setRegionLayers, handleRegionSelected } = props; const [geo, setGeo] = useState(null); const [countryData, setCountryData] = useState(null); @@ -28,8 +29,9 @@ function DashboardTrendsSidebarContainer(props) { const [countryRegions, setCountryRegions] = useState([]); const [selectedProvince, setSelectedProvince] = useState(); - const url = - `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_provinces_spi_oct4/MapServer`; + const url = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_provinces_spi_oct4/MapServer`; + // 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/gadm_drc_provinces_cm/FeatureServer' + const featureLayerURL = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/FeatureServer`; // 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; @@ -114,8 +116,9 @@ function DashboardTrendsSidebarContainer(props) { if(!regionLayers.hasOwnProperty('SPI REGIONS')) { const layer = EsriFeatureService.getTileLayer(url); - setRegionLayers({ ...regionLayers, ['SPI REGIONS']: layer }); const featureLayer = EsriFeatureService.getFeatureLayer(featureLayerURL); + setRegionLayers({ ...regionLayers, ['SPI REGIONS']: layer, ['SPI REGIONS FEATURE']: featureLayer }); + map.add(featureLayer); map.add(layer); } @@ -216,6 +219,7 @@ function DashboardTrendsSidebarContainer(props) { countryRegions={countryRegions} selectedProvince={selectedProvince} setSelectedProvince={setSelectedProvince} + allSorted={allSorted} {...props} /> ); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index 32868c572..b0ebbbfe7 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -34,6 +34,9 @@ function ProvinceChartComponent(props) { sortedByArea, sortedBySpecies, provinces, + view, + regionLayers, + handleRegionSelected, allSorted } = props; const blankData = { @@ -154,7 +157,7 @@ function ProvinceChartComponent(props) { useEffect(() => { if (allSorted && provinces.length && !selectedProvince) { setFoundIndex(0); - getProvinceScores({ value: provinces[0].value }); + handleProvinceSelected({ value: provinces[0].value }); } }, [allSorted, provinces]); @@ -194,6 +197,22 @@ function ProvinceChartComponent(props) { setBubbleData({ datasets: data }); } + const handleProvinceSelected = async (province) => { + let layerView = await view.whenLayerView(regionLayers['SPI REGIONS FEATURE']); + + const searchQuery = { + returnGeometry: true, + outFields: ["*"], + }; + + const results = await layerView.queryFeatures(searchQuery); + + const foundRegion = results.features.filter(feat => feat.attributes.NAME_1 === province.value); + handleRegionSelected({ graphic: foundRegion[0], attributes: foundRegion[0].attributes }); + + getProvinceScores(province); + } + const getProvinceScores = (province) => { const foundRegion = countryRegions.filter(region => region.region_name === province.value); const scores = foundRegion[0].regional_scores[foundRegion[0].regional_scores.length - 1]; @@ -237,7 +256,7 @@ function ProvinceChartComponent(props) { const datasetIndex = elements[0].datasetIndex; const dataIndex = elements[0].index; const value = bubbleData.datasets[datasetIndex].data[dataIndex]; - getProvinceScores({ value: value.label }); + handleProvinceSelected({ value: value.label }); setFoundIndex(provinces.findIndex(prov => prov.value === value.label)); } @@ -254,7 +273,7 @@ function ProvinceChartComponent(props) { getOptionLabel={x => x.label} getOptionValue={x => x.value} options={provinces} - onChange={getProvinceScores} + onChange={handleProvinceSelected} placeholder={t('Select Region')} /> {selectedRegionScores && <> diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index a9dc5db41..fab952c49 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -54,7 +54,7 @@ function DashboardViewComponent(props) { if (tabOption === 2) { view?.on('click', handleRegionClicked) } - }, [tabOption, view]) + }, [tabOption, view]); const handleRegionClicked = async (event) => { @@ -65,13 +65,10 @@ function DashboardViewComponent(props) { hits = await hitTest(event); if (hits) { - console.log(hits); setClickedRegion(hits.attributes); - if (highlight) { - highlight.remove(); - hoverHighlight.remove(); - } + highlight?.remove(); + hoverHighlight?.remove(); highlight = layerView.highlight(hits.graphic); } @@ -87,21 +84,24 @@ function DashboardViewComponent(props) { hits = await hitTest(event); if (hits) { - if (hoverHighlight) { - hoverHighlight.remove(); - } - + hoverHighlight?.remove(); hoverHighlight = layerView.highlight(hits.graphic); - // console.log(hits.graphic); } else { - if (hoverHighlight) { - hoverHighlight.remove(); - } + hoverHighlight?.remove(); } } } catch { } } + const handleRegionSelected = async (foundRegion) => { + let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); + + highlight?.remove(); + hoverHighlight?.remove(); + + highlight = layerView.highlight(foundRegion.graphic); + } + const hitTest = promiseUtils.debounce(async (event) => { const { results } = await view.hitTest(event); if (results.length) { @@ -142,6 +142,7 @@ function DashboardViewComponent(props) { clickedRegion={clickedRegion} tabOption={tabOption} setTabOption={setTabOption} + handleRegionSelected={handleRegionSelected} {...props} /> Date: Mon, 14 Oct 2024 08:45:34 -0400 Subject: [PATCH 144/350] adding clicking on sections --- .../dashboard-nav/dashboard-nav-component.jsx | 10 --- .../dashboard-sidebar-component.jsx | 30 +++---- .../grouped-list/grouped-list-component.jsx | 87 +++++++++++++----- .../sidebars/dashboard-sidebar/index.js | 24 +++-- .../regions-analysis-component.jsx | 52 +++++++++-- .../dashboard-trends-sidebar/index.js | 90 +++++++++---------- .../spi/spi-component.jsx | 5 -- .../province-chart-component.jsx | 18 ++-- .../dashboard-view-component.jsx | 85 +++++++++--------- .../dashboard-view/dashboard-view-config.js | 8 +- src/pages/dashboard/index.js | 4 +- src/services/esri-feature-service.ts | 48 +++++++++- src/utils/dashboard-utils.js | 18 ++++ 13 files changed, 293 insertions(+), 186 deletions(-) diff --git a/src/components/dashboard-nav/dashboard-nav-component.jsx b/src/components/dashboard-nav/dashboard-nav-component.jsx index 9fed0965d..56dace68e 100644 --- a/src/components/dashboard-nav/dashboard-nav-component.jsx +++ b/src/components/dashboard-nav/dashboard-nav-component.jsx @@ -87,16 +87,6 @@ function DashboardNavComponent(props) { > -
    }
    ); diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx index 654b2ea08..316f450d8 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx @@ -35,8 +35,18 @@ function GroupedListComponent(props) { const isActive = !dataPoints[item].isActive; const typeItems = dataPoints[item].items; + + /// TODO: added for hard code demo + const isExpertMaps = item.toUpperCase() === 'EXPERT RANGE MAPS'; + if (isExpertMaps) { + findLayerToShow(dataPoints[item].items[0]) + } + typeItems.map(item => { - findLayerToShow(item); + /// TODO: added for hard code demo, remove if statement, leave findLayerToShow method + if (!isExpertMaps) { + findLayerToShow(item); + } item.isActive = isActive; }); @@ -71,25 +81,27 @@ function GroupedListComponent(props) { }); } - if (typeof item === 'string' && item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'PROTECTED AREAS') { - if (!dataPoints[item].isActive) { - setRegionLayers({ ...regionLayers, [item.toUpperCase()]: vtLayer }); - map.add(vtLayer); - } else { - const layer = regionLayers[item.toUpperCase()]; - const { [item.toUpperCase()]: name, ...rest } = regionLayers; - setRegionLayers(rest); - map.remove(layer); - } - } else if (typeof item === 'string' && item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'ADMINISTRATIVE LAYERS') { - if (!dataPoints[item].isActive) { - setRegionLayers({ ...regionLayers, [item.toUpperCase()]: administrativeLayer }); - map.add(administrativeLayer); - } else { - const layer = regionLayers[item.toUpperCase()]; - const { [item.toUpperCase()]: name, ...rest } = regionLayers; - setRegionLayers(rest); - map.remove(layer); + if (typeof item === 'string') { + if (item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'PROTECTED AREAS') { + if (!dataPoints[item].isActive) { + setRegionLayers({ ...regionLayers, [item.toUpperCase()]: vtLayer }); + map.add(vtLayer); + } else { + const layer = regionLayers[item.toUpperCase()]; + const { [item.toUpperCase()]: name, ...rest } = regionLayers; + setRegionLayers(rest); + map.remove(layer); + } + } else if (item.toUpperCase() === 'AIRES PROTÉGÉES' || item.toUpperCase() === 'ADMINISTRATIVE LAYERS') { + if (!dataPoints[item].isActive) { + setRegionLayers({ ...regionLayers, [item.toUpperCase()]: administrativeLayer }); + map.add(administrativeLayer); + } else { + const layer = regionLayers[item.toUpperCase()]; + const { [item.toUpperCase()]: name, ...rest } = regionLayers; + setRegionLayers(rest); + map.remove(layer); + } } } }; @@ -125,6 +137,33 @@ function GroupedListComponent(props) { } } + if (layerParent === 'REGIONAL CHECKLISTS') { + if (!item.isActive) { + const webTileLayer = EsriFeatureService.getMVTSource(); + + setRegionLayers({ ...regionLayers, [layerName]: webTileLayer }); + + map.addSource('mapTiles', { + type: 'vector', + tiles: [ + 'https://production-dot-tiler-dot-map-of-life.appspot.com/0.x/tiles/regions/regions/{proj}/{z}/{x}/{y}.pbf?region_id=1673cab0-c717-4367-9db0-5c63bf26944d' + ] + }); + + + map.add({ + id: 'mvt-fill', + type: 'fill', + source: 'mapTiles' + }); + + } else { + const { [layerName]: name, ...rest } = regionLayers; + setRegionLayers(rest); + map.remove(regionLayers[layerName]); + } + } + displaySingleLayer(item) } @@ -149,14 +188,14 @@ function GroupedListComponent(props) {
    {dataPoints[key].items.length > 0 && <> -
    - + } {dataPoints[key].total_no_rows}
    - {dataPoints[key].showChildren &&
      + {key.toUpperCase() !== 'EXPERT RANGE MAPS' && dataPoints[key].showChildren &&
        {dataPoints[key].items.map((item) => (
      • findLayerToShow(item)}> { - if(!map && !view) return; + // useEffect(() => { + // if(!map && !view) return; - if(regionLayers.hasOwnProperty('SPI REGIONS') && selectedIndex !== NAVIGATION.TRENDS){ - const layer = regionLayers['SPI REGIONS']; - const featureLayer = regionLayers['SPI REGIONS FEATURE']; - const { ['SPI REGIONS']: name, ['SPI REGIONS FEATURE']: featureName, ...rest } = regionLayers; - setRegionLayers(rest); - map.remove(featureLayer); - map.remove(layer); - } - }, [map, view]); + // if(regionLayers.hasOwnProperty('SPI REGIONS') && selectedIndex !== NAVIGATION.TRENDS){ + // const layer = regionLayers['SPI REGIONS']; + // const { ['SPI REGIONS']: name, ...rest } = regionLayers; + // setRegionLayers(rest); + // map.remove(layer); + // } + // }, [map, view]); return ; diff --git a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx index cf2116ed2..649a986ca 100644 --- a/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/regions-analysis/regions-analysis-component.jsx @@ -1,4 +1,4 @@ -import React, { useContext } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import cx from 'classnames'; import Button from 'components/button'; import Radio from '@mui/material/Radio'; @@ -6,7 +6,7 @@ import RadioGroup from '@mui/material/RadioGroup'; import FormControlLabel from '@mui/material/FormControlLabel'; import SearchLocation from 'components/search-location'; import EsriFeatureService from 'services/esri-feature-service'; - +import GroupLayer from '@arcgis/core/layers/GroupLayer.js'; import { SEARCH_TYPES } from 'constants/search-location-constants'; import hrTheme from 'styles/themes/hr-theme.module.scss'; @@ -14,18 +14,51 @@ import hrTheme from 'styles/themes/hr-theme.module.scss'; import styles from './regions-analysis-styles.module.scss'; import { LightModeContext } from '../../../../context/light-mode'; import { useT } from '@transifex/react'; +import { LAYER_OPTIONS } from '../../../../utils/dashboard-utils'; function RegionsAnalysisComponent(props) { const t = useT(); - const { view, selectedOption, map } = props; + const { view, selectedOption, map, regionLayers, setRegionLayers, selectedRegionOption, setSelectedRegionOption } = props; const { lightMode } = useContext(LightModeContext); const optionSelected = (event) => { - if (event.currentTarget.value === 'protectedAreas') { - const protectedAreasURL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/VectorTileServer'; - const vtLayer = EsriFeatureService.getVectorTileLayer(protectedAreasURL); - map.add(vtLayer); + removeRegionLayers(); + let layers; + + const option = event.currentTarget.value; + if (option === 'protectedAreas') { + layers = EsriFeatureService.addProtectedAreaLayer(); + + setRegionLayers({ + [LAYER_OPTIONS.PROTECTED_AREAS]: layers.featureLayer, + [LAYER_OPTIONS.PROTECTED_AREAS_VECTOR]: layers.vectorTileLayer + }); + map.add(layers.groupLayer); + } else if (option === 'provinces') { + layers = EsriFeatureService.addProvinceLayer(); + + setRegionLayers({ + [LAYER_OPTIONS.PROVINCES]: layers.featureLayer, + [LAYER_OPTIONS.PROVINCES_VECTOR]: layers.vectorTileLayer + }); + map.add(layers.groupLayer); } + + setSelectedRegionOption(option); + } + + const removeRegionLayers = () => { + let layers = regionLayers; + Object.keys(layers).map(region => { + // const { [region]: name, ...rest } = layers; + // layers = rest; + const foundLayer = map.layers.items.find(item => item.id === region); + if (foundLayer) { + map.remove(foundLayer); + } + }); + + // setRegionLayers(layers); } return ( @@ -40,6 +73,7 @@ function RegionsAnalysisComponent(props) { aria-labelledby="demo-radio-buttons-group-label" name="radio-buttons-group" onChange={optionSelected} + value={selectedRegionOption} > } label={t('Protected Areas')} /> } label={t('Proposed Protected Areas')} /> @@ -48,7 +82,7 @@ function RegionsAnalysisComponent(props) { } label={t('Community Forests')} />
    -
    + {/*
    -
    +
    */} ); } diff --git a/src/containers/sidebars/dashboard-trends-sidebar/index.js b/src/containers/sidebars/dashboard-trends-sidebar/index.js index 76b981362..96ae3bf4c 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/index.js +++ b/src/containers/sidebars/dashboard-trends-sidebar/index.js @@ -1,14 +1,15 @@ import React, { useEffect, useState } from 'react'; import { connect } from 'react-redux'; import EsriFeatureService from 'services/esri-feature-service'; -import SearchVM from "@arcgis/core/widgets/Search/SearchViewModel.js"; +import GroupLayer from '@arcgis/core/layers/GroupLayer.js'; -import Component from './dashboard-trends-sidebar-component.jsx'; +import Component, { PROVINCE_TREND } from './dashboard-trends-sidebar-component.jsx'; import mapStateToProps from './selectors'; import { COUNTRIES_DATA_SERVICE_URL } from 'constants/layers-urls'; +import { LAYER_OPTIONS } from '../../../utils/dashboard-utils.js'; function DashboardTrendsSidebarContainer(props) { - const { countryISO, view, map, regionLayers, setRegionLayers, handleRegionSelected } = props; + const { countryISO, view, map, regionLayers, setRegionLayers } = props; const [geo, setGeo] = useState(null); const [countryData, setCountryData] = useState(null); @@ -28,13 +29,47 @@ function DashboardTrendsSidebarContainer(props) { const [allSorted, setAllSorted] = useState(false); const [countryRegions, setCountryRegions] = useState([]); const [selectedProvince, setSelectedProvince] = useState(); + const [activeTrend, setActiveTrend] = useState(PROVINCE_TREND); - const url = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_provinces_spi_oct4/MapServer`; - // 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/gadm_drc_provinces_cm/FeatureServer' + useEffect(() => { + getData(); + }, []); + useEffect(() => { + if (!countryRegions?.length) return; + getProvinces(); + }, [countryRegions]); - const featureLayerURL = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/FeatureServer`; - // 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; + // find and zoom to region + useEffect(() => { + EsriFeatureService.getFeatures({ + url: COUNTRIES_DATA_SERVICE_URL, + whereClause: `GID_0 = '${countryISO}'`, + returnGeometry: true, + }).then((features) => { + const { geometry, attributes } = features[0]; + + if (geometry && view) { + // view.center = [geometry.longitude, geometry.latitude]; + setGeo(geometry); + setCountryData(attributes); + } + }); + }, [view, countryISO]); + + useEffect(() => { + if(!map && !view) return; + + if(!regionLayers.hasOwnProperty(LAYER_OPTIONS.PROVINCES)) { + const layers = EsriFeatureService.addProvinceLayer(); + + setRegionLayers({ ...regionLayers, + [LAYER_OPTIONS.PROVINCES]: layers.featureLayer, + [LAYER_OPTIONS.PROVINCES_VECTOR]: layers.vectorTileLayer }); + + map.add(layers.groupLayer); + } + }, [map, view]); const getData = async () => { const year = '2021'; @@ -85,45 +120,6 @@ function DashboardTrendsSidebarContainer(props) { setSiiData({trendData: siiTrendData, scoresData: siiScoresData}); } - useEffect(() => { - getData(); - }, []); - - useEffect(() => { - if (!countryRegions?.length) return; - getProvinces(); - }, [countryRegions]); - - // find and zoom to region - useEffect(() => { - EsriFeatureService.getFeatures({ - url: COUNTRIES_DATA_SERVICE_URL, - whereClause: `GID_0 = '${countryISO}'`, - returnGeometry: true, - }).then((features) => { - const { geometry, attributes } = features[0]; - - if (geometry && view) { - view.center = [geometry.longitude, geometry.latitude]; - setGeo(geometry); - setCountryData(attributes); - } - }); - }, [view, countryISO]); - - useEffect(() => { - if(!map && !view) return; - - if(!regionLayers.hasOwnProperty('SPI REGIONS')) { - const layer = EsriFeatureService.getTileLayer(url); - const featureLayer = EsriFeatureService.getFeatureLayer(featureLayerURL); - setRegionLayers({ ...regionLayers, ['SPI REGIONS']: layer, ['SPI REGIONS FEATURE']: featureLayer }); - - map.add(featureLayer); - map.add(layer); - } - }, [map, view]); - const getProvinces = () => { const prov = countryRegions.map(region => { return { value: region.region_name, label: region.region_name } @@ -220,6 +216,8 @@ function DashboardTrendsSidebarContainer(props) { selectedProvince={selectedProvince} setSelectedProvince={setSelectedProvince} allSorted={allSorted} + activeTrend={activeTrend} + setActiveTrend={setActiveTrend} {...props} /> ); diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx index 4fd4a1b5d..fcec863ef 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/spi-component.jsx @@ -1,22 +1,17 @@ import React, { useState } from 'react' import ScoreDistributionsSpiComponent from './score-distibutions/score-distributions-spi-component'; -import { PROVINCE_TREND } from '../dashboard-trends-sidebar-component'; import TemporalTrendsSpiComponent from './temporal-trends/temporal-trends-spi-component'; function SpiComponent(props) { - const [activeTrend, setActiveTrend] = useState(PROVINCE_TREND); const [year, setYear] = useState(); return ( <> diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index b0ebbbfe7..524c039b1 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -14,10 +14,11 @@ import { } from 'chart.js'; import SpiArcChartComponent from 'components/charts/spi-arc-chart/spi-arc-chart-component'; - +import * as promiseUtils from "@arcgis/core/core/promiseUtils.js"; import styles from './province-chart-styles.module.scss'; import { useT } from '@transifex/react'; import { LightModeContext } from '../../../../../../context/light-mode'; +import { LAYER_OPTIONS } from '../../../../../../utils/dashboard-utils'; ChartJS.register(LinearScale, ArcElement, PointElement, Tooltip, Legend); @@ -37,6 +38,7 @@ function ProvinceChartComponent(props) { view, regionLayers, handleRegionSelected, + layerView, allSorted } = props; const blankData = { @@ -117,6 +119,7 @@ function ProvinceChartComponent(props) { const [selectedRegionScores, setSelectedRegionScores] = useState(); const [isLoading, setIsLoading] = useState(true); const [foundIndex, setFoundIndex] = useState(0); + // const [layerView, setLayerView] = useState(); useEffect(() => { if (!spiData.trendData.length) return; @@ -157,22 +160,22 @@ function ProvinceChartComponent(props) { useEffect(() => { if (allSorted && provinces.length && !selectedProvince) { setFoundIndex(0); - handleProvinceSelected({ value: provinces[0].value }); + // handleProvinceSelected({ value: provinces[0].value }); } }, [allSorted, provinces]); useEffect(() => { if (sortedBySpecies?.length && selectedProvince) { - getProvinceScores({ value: selectedProvince.region_name }); + handleProvinceSelected({ value: selectedProvince.region_name }); setFoundIndex(provinces.findIndex(prov => prov.value === selectedProvince.region_name)); } }, [sortedBySpecies]); useEffect(() => { - if (clickedRegion) { + if (clickedRegion && countryRegions.length && allSorted) { getProvinceScores({ value: clickedRegion.NAME_1 }); } - }, [clickedRegion]) + }, [clickedRegion, countryRegions, allSorted]); const getChartData = () => { const { regions } = spiData.trendData[0]; @@ -198,8 +201,6 @@ function ProvinceChartComponent(props) { } const handleProvinceSelected = async (province) => { - let layerView = await view.whenLayerView(regionLayers['SPI REGIONS FEATURE']); - const searchQuery = { returnGeometry: true, outFields: ["*"], @@ -208,8 +209,7 @@ function ProvinceChartComponent(props) { const results = await layerView.queryFeatures(searchQuery); const foundRegion = results.features.filter(feat => feat.attributes.NAME_1 === province.value); - handleRegionSelected({ graphic: foundRegion[0], attributes: foundRegion[0].attributes }); - + handleRegionSelected({ graphic: foundRegion[0] }); getProvinceScores(province); } diff --git a/src/containers/views/dashboard-view/dashboard-view-component.jsx b/src/containers/views/dashboard-view/dashboard-view-component.jsx index fab952c49..5a5fd8dbf 100644 --- a/src/containers/views/dashboard-view/dashboard-view-component.jsx +++ b/src/containers/views/dashboard-view/dashboard-view-component.jsx @@ -1,7 +1,6 @@ -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import loadable from '@loadable/component'; -import { NAVIGATION } from 'utils/dashboard-utils.js'; import CountryLabelsLayer from 'containers/layers/country-labels-layer'; import RegionsLabelsLayer from 'containers/layers/regions-labels-layer'; import SideMenu from 'containers/menus/sidemenu'; @@ -11,11 +10,14 @@ import * as promiseUtils from "@arcgis/core/core/promiseUtils.js"; import DashboardSidebarContainer from 'containers/sidebars/dashboard-sidebar' import TopMenuContainer from '../../../components/top-menu'; +import { LAYER_OPTIONS } from '../../../utils/dashboard-utils'; const { VITE_APP_ARGISJS_API_VERSION: API_VERSION } = import.meta.env; - const LabelsLayer = loadable(() => import('containers/layers/labels-layer')); + +let highlight; + function DashboardViewComponent(props) { const { activeLayers, @@ -27,7 +29,7 @@ function DashboardViewComponent(props) { isFullscreenActive, openedModal, geometry, - selectedIndex + selectedIndex, } = props; const [map, setMap] = useState(null); @@ -36,42 +38,39 @@ function DashboardViewComponent(props) { const [mapViewSettings, setMapViewSettings] = useState(viewSettings); const [clickedRegion, setClickedRegion] = useState(); const [tabOption, setTabOption] = useState(2); - - let highlight; + const [selectedRegionOption, setSelectedRegionOption] = useState(''); + const [layerView, setLayerView] = useState(); let hoverHighlight; - useEffect(() => { - if (geometry && view) { - view.center = [geometry.longitude, geometry.latitude]; - - view.on('click', handleRegionClicked); - - view.on('pointer-move', handlePointerMove); + useEffect(async () => { + if (view && Object.keys(regionLayers).length) { + const layer = await getLayerView(); + setLayerView(layer); } - }, [view, geometry]); + }, [regionLayers, view]); useEffect(() => { - if (tabOption === 2) { - view?.on('click', handleRegionClicked) - } - }, [tabOption, view]); + if (!layerView) return; + view.on('click', (event) => handleRegionClicked(event)); + view.on('pointer-move', handlePointerMove); + }, [layerView]); + const getLayerView = async () => { + return await view.whenLayerView(regionLayers[LAYER_OPTIONS.PROVINCES] || regionLayers[LAYER_OPTIONS.PROTECTED_AREAS]); + } const handleRegionClicked = async (event) => { + event.stopPropagation(); let hits; try { - if (selectedIndex === NAVIGATION.TRENDS) { - let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); - hits = await hitTest(event); + highlight?.remove(); + hoverHighlight?.remove(); - if (hits) { - setClickedRegion(hits.attributes); + hits = await hitTest(event); + if (hits) { + setClickedRegion(hits.attributes); - highlight?.remove(); - hoverHighlight?.remove(); - - highlight = layerView.highlight(hits.graphic); - } + highlight = layerView.highlight(hits.graphic); } } catch { } } @@ -79,35 +78,28 @@ function DashboardViewComponent(props) { const handlePointerMove = async (event) => { let hits; try { - if (selectedIndex === NAVIGATION.TRENDS) { - let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); - hits = await hitTest(event); - - if (hits) { - hoverHighlight?.remove(); - hoverHighlight = layerView.highlight(hits.graphic); - } else { - hoverHighlight?.remove(); - } + hits = await hitTest(event); + + if (hits) { + hoverHighlight?.remove(); + hoverHighlight = layerView.highlight(hits.graphic); + } else { + hoverHighlight?.remove(); } } catch { } } - const handleRegionSelected = async (foundRegion) => { - let layerView = await view.whenLayerView(regionLayers['SPI REGIONS']); - + const handleRegionSelected = (foundRegion) => { highlight?.remove(); - hoverHighlight?.remove(); - highlight = layerView.highlight(foundRegion.graphic); } const hitTest = promiseUtils.debounce(async (event) => { const { results } = await view.hitTest(event); if (results.length) { - const { graphic } = results.find(x => x.graphic.attributes.OBJECTID); + const { graphic } = results.find(x => x.graphic.attributes.OBJECTID || x.graphic.attributes.WDPA_PID); const { attributes } = graphic; - if (attributes.hasOwnProperty('region_name')) { + if (attributes.hasOwnProperty('region_name') || attributes.hasOwnProperty('WDPA_PID')) { return { graphic, attributes } } else { return null; @@ -143,6 +135,9 @@ function DashboardViewComponent(props) { tabOption={tabOption} setTabOption={setTabOption} handleRegionSelected={handleRegionSelected} + selectedRegionOption={selectedRegionOption} + setSelectedRegionOption={setSelectedRegionOption} + layerView={layerView} {...props} /> { if(!scientificName) return; - localStorage.setItem('selected_species', scientificName); + localStorage.setItem(SPECIES_SELECTED_COOKIE, scientificName); setSpeciesName(scientificName); }, [scientificName]) diff --git a/src/services/esri-feature-service.ts b/src/services/esri-feature-service.ts index bcb7f67d7..47b6a9c8b 100644 --- a/src/services/esri-feature-service.ts +++ b/src/services/esri-feature-service.ts @@ -1,9 +1,14 @@ import { LAYERS_URLS } from 'constants/layers-urls'; import { LOCAL_SPATIAL_REFERENCE } from 'constants/scenes-constants'; import { AddFeature, GetFeatures, GetLayer } from 'types/services-types'; +import { + LAYER_OPTIONS, PROTECTED_AREA_FEATURE_URL, PROTECTED_AREA_VECTOR_URL, + PROVINCE_FEATURE_LAYER_URL, PROVINCE_VECTOR_URL +} from 'utils/dashboard-utils.js'; import FeatureLayer from '@arcgis/core/layers/FeatureLayer'; import GeoJSONLayer from '@arcgis/core/layers/GeoJSONLayer'; +import GroupLayer from '@arcgis/core/layers/GroupLayer'; import TileLayer from '@arcgis/core/layers/TileLayer'; import VectorTileLayer from '@arcgis/core/layers/VectorTileLayer'; import WebTileLayer from '@arcgis/core/layers/WebTileLayer'; @@ -44,16 +49,18 @@ function getFeatures({ }); } -function getVectorTileLayer(url){ +function getVectorTileLayer(url, id){ return new VectorTileLayer({ url, + id, }); } -function getFeatureLayer(url){ +function getFeatureLayer(url, id){ return new FeatureLayer({ url, outFields: ['*'], + id, }); } @@ -69,7 +76,16 @@ async function getXYZLayer(scientificname){ return new WebTileLayer({ urlTemplate: data.url - }) + }); +} + +function getMVTSource(scientificname){ + return { + type: 'vector', + tiles: [ + 'https://production-dot-tiler-dot-map-of-life.appspot.com/0.x/tiles/regions/regions/{proj}/{z}/{x}/{y}.pbf?region_id=1673cab0-c717-4367-9db0-5c63bf26944d' + ] + }; } function getTileLayer(url){ @@ -121,6 +137,29 @@ function addFeature({ url, features }: AddFeature) { }); } +function addProvinceLayer(){ + const featureLayer = getFeatureLayer(PROVINCE_FEATURE_LAYER_URL, LAYER_OPTIONS.PROVINCES); + const vectorTileLayer = getVectorTileLayer(PROVINCE_VECTOR_URL, LAYER_OPTIONS.PROVINCES_VECTOR); + const groupLayer = new GroupLayer({ + layers: [featureLayer, vectorTileLayer], + id: LAYER_OPTIONS.PROVINCES + }); + + return { groupLayer, featureLayer, vectorTileLayer }; +} + +function addProtectedAreaLayer(){ + const featureLayer = getFeatureLayer(PROTECTED_AREA_FEATURE_URL, LAYER_OPTIONS.PROTECTED_AREAS); + const vectorTileLayer = getVectorTileLayer(PROTECTED_AREA_VECTOR_URL, LAYER_OPTIONS.PROTECTED_AREAS_VECTOR); + + const groupLayer = new GroupLayer({ + layers: [featureLayer], + id: LAYER_OPTIONS.PROTECTED_AREAS, + }); + + return { groupLayer, featureLayer, vectorTileLayer }; +} + export default { getFeatures, getLayer, @@ -130,4 +169,7 @@ export default { getVectorTileLayer, getXYZLayer, getTileLayer, + getMVTSource, + addProvinceLayer, + addProtectedAreaLayer, }; diff --git a/src/utils/dashboard-utils.js b/src/utils/dashboard-utils.js index 0a04f9c7b..444cd7b5b 100644 --- a/src/utils/dashboard-utils.js +++ b/src/utils/dashboard-utils.js @@ -9,3 +9,21 @@ export const NAVIGATION = { REGION_ANALYSIS: 6, TRENDS: 7, } + +export const LAYER_OPTIONS = { + PROTECTED_AREAS: 'PROTECTED_AREAS', + PROTECTED_AREAS_VECTOR: 'PROTECTED_AREAS_VECTOR', + PROPOSED_PROTECTED_AREAS: 'PROPOSED_PROTECTED_AREAS', + PROVINCES: 'PROVINCES', + PROVINCES_VECTOR: 'PROVINCES_VECTOR', + PRIORITY_AREAS: 'PRIORITY_AREAS', + COMMUNITY_FORESTS: 'COMMUNITY_FORESTS', +} + +export const PROVINCE_FEATURE_LAYER_URL = `https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/FeatureServer`; +export const PROVINCE_VECTOR_URL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join/VectorTileServer'; + +export const PROTECTED_AREA_FEATURE_URL = 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/FeatureServer'; +export const PROTECTED_AREA_VECTOR_URL = 'https://vectortileservices9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/DRC_WDPA_all/VectorTileServer'; + + From c4419036df143cbb891b2354c0f59e8cad75887d Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 08:48:31 -0400 Subject: [PATCH 145/350] select default region on load --- .../temporal-trends/province-chart/province-chart-component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx index 524c039b1..05615bbde 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/spi/temporal-trends/province-chart/province-chart-component.jsx @@ -160,7 +160,7 @@ function ProvinceChartComponent(props) { useEffect(() => { if (allSorted && provinces.length && !selectedProvince) { setFoundIndex(0); - // handleProvinceSelected({ value: provinces[0].value }); + handleProvinceSelected({ value: provinces[0].value }); } }, [allSorted, provinces]); From b091f981fbf8046792b18c0aa9e20d885d6714ea Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 09:14:28 -0400 Subject: [PATCH 146/350] simple login form --- .../dashboard-login-component.jsx | 56 +++++++++++++++++++ .../dashboard-login-styles.module.scss | 36 ++++++++++++ src/components/dashboard-login/index.js | 10 ++++ src/pages/dashboard/dashboard-component.jsx | 8 ++- src/pages/dashboard/index.js | 3 + 5 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 src/components/dashboard-login/dashboard-login-component.jsx create mode 100644 src/components/dashboard-login/dashboard-login-styles.module.scss create mode 100644 src/components/dashboard-login/index.js diff --git a/src/components/dashboard-login/dashboard-login-component.jsx b/src/components/dashboard-login/dashboard-login-component.jsx new file mode 100644 index 000000000..dc58a155a --- /dev/null +++ b/src/components/dashboard-login/dashboard-login-component.jsx @@ -0,0 +1,56 @@ +import React, { useState } from 'react'; +import styles from './dashboard-login-styles.module.scss'; +import FormControl from '@mui/material/FormControl'; +import TextField from '@mui/material/TextField'; +import Button from 'components/button'; +import { useT } from '@transifex/react'; +import Logo from '../half-earth-logo/component'; + +function DashboardLoginComponent(props) { + const { setLoggedIn } = props; + const t = useT(); + + const [email, setEmail] = useState(); + const [password, setPassword] = useState() + + const handleLogin = () => { + setLoggedIn(true); + } + + return ( +
    + +
    + + { + setEmail(event.target.value); + }} + /> + + + { + setPassword(event.target.value); + }} + /> + +
    +
    + ) +} + +export default DashboardLoginComponent diff --git a/src/components/dashboard-login/dashboard-login-styles.module.scss b/src/components/dashboard-login/dashboard-login-styles.module.scss new file mode 100644 index 000000000..874deae47 --- /dev/null +++ b/src/components/dashboard-login/dashboard-login-styles.module.scss @@ -0,0 +1,36 @@ +@import 'styles/ui.module'; +@import 'styles/settings'; +@import 'styles/typography-extends'; +@import 'styles/common-animations.module'; + +.container{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 10px; + height: 100vh; + + --border-color: #{$brand-color-main}; + --save-button-text: #{$dark-text}; + --border-color-hover: #{$brand-color-main-hover}; + + .loginForm{ + display: flex; + flex-direction: column; + background: $white; + width: 400px; + padding: 10px; + gap: 10px; + border-radius: 8px; + + .saveButton { + color: var(--save-button-text); + background-color: var(--border-color); + &:hover { + background-color: var(--border-color-hover); + color: var(--save-button-text); + } + } + } +} diff --git a/src/components/dashboard-login/index.js b/src/components/dashboard-login/index.js new file mode 100644 index 000000000..936c3cfcb --- /dev/null +++ b/src/components/dashboard-login/index.js @@ -0,0 +1,10 @@ +import React from 'react' +import DashboardLoginComponent from './dashboard-login-component' + +function DashboardLogin(props) { + return ( + + ) +} + +export default DashboardLogin diff --git a/src/pages/dashboard/dashboard-component.jsx b/src/pages/dashboard/dashboard-component.jsx index a161cd926..96eda5634 100644 --- a/src/pages/dashboard/dashboard-component.jsx +++ b/src/pages/dashboard/dashboard-component.jsx @@ -1,19 +1,23 @@ import React from 'react'; import DashboardView from '../../containers/views/dashboard-view/dashboard-view'; +import DashboardLogin from '../../components/dashboard-login'; function DashboardComponent(props) { const { activeLayers, handleMapLoad, + loggedIn, + setLoggedIn, } = props; return ( <> - } + {loggedIn && handleMapLoad(map, activeLayers)} {...props} - /> + />} ); } diff --git a/src/pages/dashboard/index.js b/src/pages/dashboard/index.js index 4323954a0..f435f39c9 100644 --- a/src/pages/dashboard/index.js +++ b/src/pages/dashboard/index.js @@ -38,6 +38,7 @@ function DashboardContainer(props) { const [filteredTaxaList, setFilteredTaxaList] = useState(); const [speciesName, setSpeciesName] = useState(null); const [selectedIndex, setSelectedIndex] = useState(NAVIGATION.HOME); + const [loggedIn, setLoggedIn] = useState(false); const speciesListUrl = 'https://next-api-dot-api-2-x-dot-map-of-life.appspot.com/2.x/spatial/species/list'; @@ -332,6 +333,8 @@ function DashboardContainer(props) { setSpeciesName={setSpeciesName} selectedIndex={selectedIndex} setSelectedIndex={setSelectedIndex} + loggedIn={loggedIn} + setLoggedIn={setLoggedIn} {...props} />; } From df46f41013a6cb5fa20b6c8c8ffa70b077812cf5 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 09:36:34 -0400 Subject: [PATCH 147/350] login page and favicon --- favicon.ico | Bin 1947 -> 15406 bytes index.html | 2 +- public/favicon.ico | Bin 1947 -> 15406 bytes public/manifest.json | 4 ++-- src/assets/logos/institut-congolais.png | Bin 0 -> 104926 bytes .../dashboard-login-component.jsx | 6 ++++-- 6 files changed, 7 insertions(+), 5 deletions(-) create mode 100644 src/assets/logos/institut-congolais.png diff --git a/favicon.ico b/favicon.ico index 8461691f142eec3bd07bf093e37b71ef6afb40cc..466e55f280e10f5d60587f3ab910514f61d945e8 100644 GIT binary patch literal 15406 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 literal 1947 zcmV;M2W0q(P)T#Rmvuo{U=dXAUH}`3(I`%BOp9W@ zC1cx2n%cC}ncQr~h@bMQ>4#3+=>(H@CN@o@A3BqyHdCXujj$MXyd*VI%mu5&qTFu_ z!gASV&*kk0U|C?fO#d_I!+GB4eg6OFIq&nlM=($9JGIy8jvHE|DCSxu1;?s??p?S1 zvP%&bs%iwT-rCd_47=(O;;NL^O`~$FF`u}$xg4Ia*|ka)`irJHxaW3rQHp7)B*%AS z8Y}ABAUB%2#qYjFm33D z0{|&ub?!A9+E<{dx{~PbU2jv2@`v^nT>R`W_3cx+l&OaOH9LN+D*8VJGG*N6atu?p z_7qNgkouNF3`2{QFKjp%3MEXGR7e0et*XIyZ5KU(RD_V(HZ^=<|Jfa-Q~4%+f){Fb zY*!Wiq?mFx28I);Yh2Ax$jzPB0_1evQy_6@A)NLgWou93iSHS+GH96gM~-YceSMmM zXRCK-+SO345O|_PHFoB5_QrO?x^oWF$=LkB8Pbzm7z(-R8}v|+`NcS8Lr`};_~&gW z0uYtyV9@<)a(u|sHl6L8vM_*lu*#02Jd9*N$a2BxVJy!3l%lK~IP5_>dKXjs-}Q`yoqQwrdN?nm ze%YH_Pc@BK;6RewPhDd%QYzSOA#OFVqN^``3b{ClY5ZP){kv9lw))|+FmQ<<9KWJ1 zP4Y?PTltG`DQj0;MpH-UQC8YrveFs=FfG+Cgm@l!SiRZ1Xusj(g#mR$R{8GfvQ*ttnw%S{*+BYuu*{f zUsw0g+LMW04P#n1TK!p+6kH(Q6&TyA9OE}TXC{xrLU;dP$J=ox2qCi<#t*EtA=xlm z7L6-)o7q)zoQ96&^bVwO@ypVQmXp>It)lwIjH7c55Mu-n4qrq`n=z|B>`#UM#I!7 z%KDu6xPgeHs#tgvJIK$tOwy(yjB=gl+*?O>H%d+E%q zceetZmk^q|;176d?_CmkSA}u-nX1P-Fqu2$ijv3C`{a!W68X8Mv~ zIO;G8A@d!!;6ILT#g7jTf2ihZ3Uz6FbsSKq6?&((QIcJ)siP4eVYVVe}f?%Wk*U+-I-j0^RHMS zUX(Bxz0Dt(7$i+yx!h@68LiwU;9COueF58MCI^8e&M}N7MegU!*#bUoyRN zOTAX%`}yEU9qv%3cP835@7*8NhDf=0pW1L>wQh zgau$)HX1wg07-LK&i_RYqqC(akj97}hlCmduSM2kZO|%wdq5r&ke~>Yob<2p_j~Cd zns*n*ghad#@@c(tYvgp#SX1qgFBi${Aa_o7ihZ@tPD~$&m%;jzURgG2n$8(XJLLN& zQXWWf_3vE1xX$TK?BL>8-(e^ek5da`Nd;9g8POd$?IF?<+i2{{!?bKjXae!J5aNyS ztEK)}@#me&)2GWl?zq6W1=c1hMd5JBow*=xzyrcAC5CQl0lO{S0W{ofTwQyyZp(RT hnKz8XWwTyZ{{st_=9uzSjk5p%002ovPDHLkV1f@sshj`+ diff --git a/index.html b/index.html index a290d99ad..45e44b096 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,7 @@ - Half-Earth Project Map + ICCN Biodiversité nationale diff --git a/public/favicon.ico b/public/favicon.ico index 8461691f142eec3bd07bf093e37b71ef6afb40cc..466e55f280e10f5d60587f3ab910514f61d945e8 100644 GIT binary patch literal 15406 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 literal 1947 zcmV;M2W0q(P)T#Rmvuo{U=dXAUH}`3(I`%BOp9W@ zC1cx2n%cC}ncQr~h@bMQ>4#3+=>(H@CN@o@A3BqyHdCXujj$MXyd*VI%mu5&qTFu_ z!gASV&*kk0U|C?fO#d_I!+GB4eg6OFIq&nlM=($9JGIy8jvHE|DCSxu1;?s??p?S1 zvP%&bs%iwT-rCd_47=(O;;NL^O`~$FF`u}$xg4Ia*|ka)`irJHxaW3rQHp7)B*%AS z8Y}ABAUB%2#qYjFm33D z0{|&ub?!A9+E<{dx{~PbU2jv2@`v^nT>R`W_3cx+l&OaOH9LN+D*8VJGG*N6atu?p z_7qNgkouNF3`2{QFKjp%3MEXGR7e0et*XIyZ5KU(RD_V(HZ^=<|Jfa-Q~4%+f){Fb zY*!Wiq?mFx28I);Yh2Ax$jzPB0_1evQy_6@A)NLgWou93iSHS+GH96gM~-YceSMmM zXRCK-+SO345O|_PHFoB5_QrO?x^oWF$=LkB8Pbzm7z(-R8}v|+`NcS8Lr`};_~&gW z0uYtyV9@<)a(u|sHl6L8vM_*lu*#02Jd9*N$a2BxVJy!3l%lK~IP5_>dKXjs-}Q`yoqQwrdN?nm ze%YH_Pc@BK;6RewPhDd%QYzSOA#OFVqN^``3b{ClY5ZP){kv9lw))|+FmQ<<9KWJ1 zP4Y?PTltG`DQj0;MpH-UQC8YrveFs=FfG+Cgm@l!SiRZ1Xusj(g#mR$R{8GfvQ*ttnw%S{*+BYuu*{f zUsw0g+LMW04P#n1TK!p+6kH(Q6&TyA9OE}TXC{xrLU;dP$J=ox2qCi<#t*EtA=xlm z7L6-)o7q)zoQ96&^bVwO@ypVQmXp>It)lwIjH7c55Mu-n4qrq`n=z|B>`#UM#I!7 z%KDu6xPgeHs#tgvJIK$tOwy(yjB=gl+*?O>H%d+E%q zceetZmk^q|;176d?_CmkSA}u-nX1P-Fqu2$ijv3C`{a!W68X8Mv~ zIO;G8A@d!!;6ILT#g7jTf2ihZ3Uz6FbsSKq6?&((QIcJ)siP4eVYVVe}f?%Wk*U+-I-j0^RHMS zUX(Bxz0Dt(7$i+yx!h@68LiwU;9COueF58MCI^8e&M}N7MegU!*#bUoyRN zOTAX%`}yEU9qv%3cP835@7*8NhDf=0pW1L>wQh zgau$)HX1wg07-LK&i_RYqqC(akj97}hlCmduSM2kZO|%wdq5r&ke~>Yob<2p_j~Cd zns*n*ghad#@@c(tYvgp#SX1qgFBi${Aa_o7ihZ@tPD~$&m%;jzURgG2n$8(XJLLN& zQXWWf_3vE1xX$TK?BL>8-(e^ek5da`Nd;9g8POd$?IF?<+i2{{!?bKjXae!J5aNyS ztEK)}@#me&)2GWl?zq6W1=c1hMd5JBow*=xzyrcAC5CQl0lO{S0W{ofTwQyyZp(RT hnKz8XWwTyZ{{st_=9uzSjk5p%002ovPDHLkV1f@sshj`+ diff --git a/public/manifest.json b/public/manifest.json index 224109c11..df06e90ea 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -1,6 +1,6 @@ { - "short_name": "Half Earth Map", - "name": "Half-Earth Project Map", + "short_name": "ICCN Biodiversité nationale", + "name": "ICCN Biodiversité nationale", "icons": [ { "src": "favicon.ico", diff --git a/src/assets/logos/institut-congolais.png b/src/assets/logos/institut-congolais.png new file mode 100644 index 0000000000000000000000000000000000000000..325d35d8dc21b56a850549f4e88b1cc660089bd2 GIT binary patch literal 104926 zcmX_HWmr^Q*B(JSRJxIt?oR3Ma7d-QyOC~?mX?z4F6r*>?(T-~pwIiAA28Q7YtCN# zUa?p0V0l?FBzPQn5D0`MAug;40zm;EAp~Hdfq&z;1Lz>oN05Z@XJzO4!zCDZ)T;-W z)5ZbWWVR(YX307K3WJmI@9>|Pgq7bzp?}t|m-osDLWK!JFdz}SUe5AG{*>c(vUE7` z@{rTTuj> zWVI!0NJHUKE)}(HBtl)LNlDXR?1#vC8z-Y_5X7BT9@C-Vta6+D2}BTF9j~5lSDwz> zn+q??^%>(Z5#D4xTkxNDpqe!=7M00CfItFSfe;@-AQqRr((GOorBLI~BXN}Ur(@q! zX((C;&jO3rs;rGhVlhvPsN?q>QmE;Y;Y-#Txi`>ZjL|d`&k2!VH;==M26_X^=o25H z`f$vHCWPQzg8o_Kn3I4n`72?v@>ijF-lP}$<1tltP+xSGf z)aPjv0`ye1lTOC$f~!Ww5ZtP6jWj+e>LdK6&anMQZGCFrv{8;AQQZ5B9*z))f{wht zVA6HoApzsAh>GsbKU$nusJvYh(p373Zy)iF`f|9h{lT)67WmZPo@t`Z;j$r83JSue_8Qt!P?5G)AfupXN3 z8}}gF=|CRZEO99@LT6#Xa9TA=Q3yMj2KSdz{@q^|)ETkDXzIU?XiK5f-*2MfHD(-5W5W*_NQp4gwaCMN zR4jC_DEuMW+AN&?g;JbCnV#6OepmbMYG9BOzb)43#6dLRA0-a`UwJ6HK$)^J7WaOq znSZHbZa>9xwQk0XU%R_F?v2o| zf2XuOJ_3gg=n3!`yZ%)|!zCN`(_nJL*w~BmRxcT)Fgt>nLFrI%UGw!}l z4Z7;>Q>#{Q<*Z8;X~1^d<b3OyM-(I%kpb&HMvw z)ssU30F2n)HEoDqSt>G3&i;1wAe5vp7gM~7j7Ze+-^*4%|Ak@`u_-!Sib{S_viAmj zd6xe{e}WXn=Ra6M%22P;4F4jo9IyASyxZ=$Kdb8Wh9)?^_tlL6k21_(g3-7G>|uYh zpWd}IDcC9n<73Ay&;KKteEXLKmiCb>2i@WMc;rAxi7AATBAG|L?0@S_qWz@-9qr@d zCCzP|D4qFQb#9Lzw=Ca={R0T3^rw#uBmmifoowW?s;qeu^}EQXEjkIZmz@9qQ3Odt z0aEjZj`|5EUOE-~B5$jHHajpg0TUzhhP3m4izVW`E_NlJGi?|8;?$s}5Nx=;b%5>B zmy1D)_CKOY^jDqV?`u-&!9xg{v=jVQLHk8H|68BmfaQtr;cFBq>UL_N(J!xVOn!lfJz!yG<`yZCe7t~+$0KlS5n;Qw$}dOhw~+;R-K zY|`^;?HRCchoF~d1I%@!fzadiVZa0&gg|9ns#>>674$-$_7b;7Au|nma#7U(DA@l} z#Kx+Ux*hqV7H4go$N!ir2lVwn8%rbsn8=t5mKb!>EI(cx-K}f#*RST~L-+^RpOm$1 zOwiBpgWJynC>q@T#{11#r%i0xF~g&i@~_qyx!dZ zHwc#3eRzZW=@k*wO88gKF5_a=`u4?99RIfu7O_`?IR!Js@BV~oc zit$5+?|+*U*a86ZCMV;T>+-k}OWZkevjPmmh+&KQ=|3L-K)xEWjHqmj0tg_}~pLdpOlO>1jt^ ztNM##`sK_O|I`R1@A3ETSKDHF+FZ_D&juB<$a8j96JiF zILD9os|Igw-|+@3qXeU8mV6m8{?n6PIKcmWzaK+S$eVtPVa4LQy7iZLyYtIz3E4UD z+$B%q)!CKGQ<;e#8sG&TB%F;WI){*~TWOTE-)6U|Xol=<0WNpGhji14bO2v`bRgb2 zDFZv?;|J08hVW{Z!$^lLE5cjT-K*)q8N_5j>+Pb?;q0vgEfPYi=CO>&>@ zAY6s}?S&I`8ocRAic~xj%a?f8FTEnrm2z+A+QNA{XtnKJhclVaq!6LAxUcPixTn*T z2MC$1TZZ{}a%0D3F9bfmjU{OPhmFov^7fD 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%0D|es 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 Jd8PI7{{UoU9`^tM literal 0 HcmV?d00001 diff --git a/src/components/dashboard-login/dashboard-login-component.jsx b/src/components/dashboard-login/dashboard-login-component.jsx index dc58a155a..be08306d3 100644 --- a/src/components/dashboard-login/dashboard-login-component.jsx +++ b/src/components/dashboard-login/dashboard-login-component.jsx @@ -3,8 +3,8 @@ import styles from './dashboard-login-styles.module.scss'; import FormControl from '@mui/material/FormControl'; import TextField from '@mui/material/TextField'; import Button from 'components/button'; +import iccnLogo from 'logos/institut-congolais.png'; import { useT } from '@transifex/react'; -import Logo from '../half-earth-logo/component'; function DashboardLoginComponent(props) { const { setLoggedIn } = props; @@ -19,7 +19,9 @@ function DashboardLoginComponent(props) { return (

    - +
    + +
    Date: Mon, 14 Oct 2024 09:42:55 -0400 Subject: [PATCH 148/350] remove conservation metrics and country title --- .../dashboard-trends-sidebar-component.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx index ec502ba9d..e0b735119 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component.jsx @@ -18,8 +18,8 @@ function DashboardTrendsSidebar(props) {
    - {t('Conservation Metrics')} - + {/* {t('Conservation Metrics')} + */}
    } + {dataPoints[key].total_no_rows}
    - {key.toUpperCase() !== 'EXPERT RANGE MAPS' && dataPoints[key].showChildren &&
      + {dataPoints[key].showChildren &&
        {dataPoints[key].items.map((item) => (
      • findLayerToShow(item)}> Date: Mon, 14 Oct 2024 10:07:54 -0400 Subject: [PATCH 150/350] Use translation for DRC title --- .../sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 009807ed3..4670f696f 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -134,7 +134,7 @@ function DashboardSidebar(props) { {lightMode && } {/*

        {countryName}

        */} -

        République démocratique du Congo

        +

        {t('Democratic Republic of the Congo')}

        From 7141c6b80f37c7a82d1ed2f59f815fb2e768f23d Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 10:21:17 -0400 Subject: [PATCH 151/350] remove provinces on switch --- .../dashboard-sidebar-component.jsx | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx index 4670f696f..284b34366 100644 --- a/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/dashboard-sidebar-component.jsx @@ -15,7 +15,7 @@ import SpeciesListContainer from '../../../components/species-list'; import DashboardNav from '../../../components/dashboard-nav'; import DashboardHomeContainer from './dashboard-home'; import DashboardTrendsSidebarContainer from 'containers/sidebars/dashboard-trends-sidebar'; -import { NAVIGATION } from '../../../utils/dashboard-utils'; +import { LAYER_OPTIONS, NAVIGATION } from '../../../utils/dashboard-utils'; function DashboardSidebar(props) { const t = useT(); @@ -116,16 +116,24 @@ function DashboardSidebar(props) { setIsLoading(false); }, [taxaList]); - // useEffect(() => { - // if (regionLayers.hasOwnProperty('SPI REGIONS') && selectedIndex !== NAVIGATION.TRENDS) { - // const layer = regionLayers['SPI REGIONS']; - // const { ['SPI REGIONS']: name, ...rest } = regionLayers; - // setRegionLayers(rest); - // map.remove(layer); - // } - - // }, [selectedIndex]) + useEffect(() => { + if (regionLayers.hasOwnProperty(LAYER_OPTIONS.PROVINCES) && selectedIndex !== NAVIGATION.TRENDS) { + removeRegionLayers(); + setRegionLayers({}); + } + }, [selectedIndex]); + const removeRegionLayers = () => { + let layers = regionLayers; + Object.keys(layers).map(region => { + // const { [region]: name, ...rest } = layers; + // layers = rest; + const foundLayer = map.layers.items.find(item => item.id === region); + if (foundLayer) { + map.remove(foundLayer); + } + }); + } return (
        From 1412f75f671f4e0724bc241ef57e81e5d873e1fa Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 10:22:40 -0400 Subject: [PATCH 152/350] toggle off text --- .../sii/temporal-trends/temporal-trends-sii-component.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/containers/sidebars/dashboard-trends-sidebar/sii/temporal-trends/temporal-trends-sii-component.jsx b/src/containers/sidebars/dashboard-trends-sidebar/sii/temporal-trends/temporal-trends-sii-component.jsx index 35e42613f..7d432bdaf 100644 --- a/src/containers/sidebars/dashboard-trends-sidebar/sii/temporal-trends/temporal-trends-sii-component.jsx +++ b/src/containers/sidebars/dashboard-trends-sidebar/sii/temporal-trends/temporal-trends-sii-component.jsx @@ -67,9 +67,9 @@ function TemporalTrendsSiiComponent(props) { label={NATIONAL_TREND} />
        - + {/* {t('Toggle national SPI and province-level breakdown.')} - + */} {/* {selectedIndex >= NAVIGATION.SPECIES && selectedIndex <= NAVIGATION.REGION_ANALYSIS &&
        } @@ -97,7 +96,7 @@ function DashboardNavComponent(props) { })} onClick={() => updateHistory(NAVIGATION.TRENDS, titles.TRENDS)} > - +
        diff --git a/src/components/dashboard-nav/dashboard-nav-styles.module.scss b/src/components/dashboard-nav/dashboard-nav-styles.module.scss index 1c5b0659e..e2eb41428 100644 --- a/src/components/dashboard-nav/dashboard-nav-styles.module.scss +++ b/src/components/dashboard-nav/dashboard-nav-styles.module.scss @@ -47,6 +47,19 @@ width: 30px; height: 30px; fill: var(--svg-fill); + + rect{ + width: 50px; + height: 50px; + } + } + + &[aria-label="Species"]{ + svg{ + width: 50px; + height: 50px; + margin-left: -7px; + } } &.selected, From e8c87cf308a20d9e601d8ce148e823d205d37812 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 11:07:15 -0400 Subject: [PATCH 155/350] translations --- src/components/dashboard-login/dashboard-login-component.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/dashboard-login/dashboard-login-component.jsx b/src/components/dashboard-login/dashboard-login-component.jsx index be08306d3..164fa5073 100644 --- a/src/components/dashboard-login/dashboard-login-component.jsx +++ b/src/components/dashboard-login/dashboard-login-component.jsx @@ -26,7 +26,7 @@ function DashboardLoginComponent(props) { { setEmail(event.target.value); @@ -36,7 +36,7 @@ function DashboardLoginComponent(props) { { From 6262a0c96708ed126834ed34520461df143fd9d2 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 12:28:54 -0400 Subject: [PATCH 156/350] language upate --- src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx b/src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx index b2d527d81..0d3bca3f7 100644 --- a/src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx +++ b/src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx @@ -90,7 +90,7 @@ function SpiArcChartComponent(props) { {species}
        {t('Species Richness:')}
        - {scores[species].total} {species} + {scores[species].total} {t(species)}
    )} From 193a3875112c14885a0689f396d097c8ffacaa62 Mon Sep 17 00:00:00 2001 From: Chris Manciero Date: Mon, 14 Oct 2024 14:50:24 -0400 Subject: [PATCH 157/350] disable any range map ids not found in array --- .../data-layers/data-layers-component.jsx | 18 ++++---- .../grouped-list/grouped-list-component.jsx | 41 ++++++++++++------- .../grouped-list-styles.module.scss | 10 +++++ 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx index ce31a2c8b..681211eaa 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/data-layers-component.jsx @@ -74,15 +74,15 @@ function DataLayerComponent(props) { } obj.isActive = false; /// TODO: Remove Expert Range Maps restriction - if (key.toUpperCase() === 'EXPERT RANGE MAPS') { - if (acc[key].items < 2) { - acc[key].items.push(obj); - acc[key].total_no_rows += obj.no_rows || 0; // Summing the no_rows property - } - } else { - acc[key].items.push(obj); - acc[key].total_no_rows += obj.no_rows || 0; // Summing the no_rows property - } + // if (key.toUpperCase() === 'EXPERT RANGE MAPS') { + // if (acc[key].items < 2) { + // acc[key].items.push(obj); + // acc[key].total_no_rows += obj.no_rows || 0; // Summing the no_rows property + // } + // } else { + acc[key].items.push(obj); + acc[key].total_no_rows += obj.no_rows || 0; // Summing the no_rows property + // } return acc; }, {}); } diff --git a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx index 5970cc9fa..37a6e8bb7 100644 --- a/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx +++ b/src/containers/sidebars/dashboard-sidebar/data-layers/grouped-list/grouped-list-component.jsx @@ -12,6 +12,11 @@ function GroupedListComponent(props) { const { dataPoints, setDataPoints, map, speciesInfo, regionLayers, setRegionLayers } = props; const t = useT(); + const expertRangeMapIds = ['ec694c34-bddd-4111-ba99-926a5f7866e8', + '0ed89f4f-3ed2-41c2-9792-7c7314a55455', + '98f229de-6131-41ef-aff1-7a52212b5a15', + 'd542e050-2ae5-457e-8476-027741538965'] + const displayChildren = (key) => { const showChildren = !dataPoints[key].showChildren; @@ -36,17 +41,8 @@ function GroupedListComponent(props) { const typeItems = dataPoints[item].items; - /// TODO: added for hard code demo - // const isExpertMaps = item.toUpperCase() === 'EXPERT RANGE MAPS'; - // if (isExpertMaps) { - // findLayerToShow(dataPoints[item].items[0]) - // } - typeItems.map(item => { - /// TODO: added for hard code demo, remove if statement, leave findLayerToShow method - // if (!isExpertMaps) { findLayerToShow(item); - // } item.isActive = isActive; }); @@ -182,6 +178,25 @@ function GroupedListComponent(props) { return typeItems; } + const getCheckbox = (item) => { + let control = findLayerToShow(item)} checked={item.isActive} />} + /> + + if (item.type_title.toUpperCase() === 'EXPERT RANGE MAPS') { + if (!expertRangeMapIds.find((id) => id === item.dataset_id)) { + control = } + /> + } + } + + return control; + } + return (
    {Object.keys(dataPoints).map((key) => ( @@ -212,11 +227,9 @@ function GroupedListComponent(props) {
    {dataPoints[key].showChildren &&