diff --git a/.eslintrc.js b/.eslintrc.cjs
similarity index 100%
rename from .eslintrc.js
rename to .eslintrc.cjs
diff --git a/.prettierrc.js b/.prettierrc.cjs
similarity index 100%
rename from .prettierrc.js
rename to .prettierrc.cjs
diff --git a/favicon-DRC.ico b/favicon-DRC.ico
new file mode 100644
index 000000000..466e55f28
Binary files /dev/null and b/favicon-DRC.ico differ
diff --git a/favicon.ico b/favicon.ico
index 8461691f1..e74167870 100644
Binary files a/favicon.ico and b/favicon.ico differ
diff --git a/index.html b/index.html
index a290d99ad..e383433d6 100644
--- a/index.html
+++ b/index.html
@@ -2,7 +2,6 @@
-
@@ -18,8 +17,6 @@
-
- Half-Earth Project Map
diff --git a/package.json b/package.json
index c7149f0ae..27d8d0407 100644
--- a/package.json
+++ b/package.json
@@ -5,15 +5,21 @@
"type": "module",
"dependencies": {
"@arcgis/core": "4.30.0",
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.0",
"@esri/arcgis-rest-feature-layer": "^3.4.3",
"@esri/arcgis-rest-request": "^3.4.3",
"@loadable/component": "^5.10.1",
+ "@mui/icons-material": "^6.0.2",
+ "@mui/material": "^6.0.2",
"@tanstack/react-query": "^4.1.0",
"@tippyjs/react": "^4.2.5",
"@transifex/native": "^4.1.0",
"@transifex/react": "^4.1.0",
+ "@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.3.1",
"assert": "^2.0.0",
+ "chart.js": "^4.4.3",
"classnames": "^2.2.6",
"contentful": "^7.6.0",
"cross-var": "^1.1.0",
@@ -30,6 +36,7 @@
"qs": "^6.7.0",
"rc-slider": "^9.7.2",
"react": "17.0.2",
+ "react-chartjs-2": "^5.2.0",
"react-copy-to-clipboard": "^5.0.1",
"react-dom": "^17.0.2",
"react-dropzone": "^11.4.0",
diff --git a/public/favicon-DRC.ico b/public/favicon-DRC.ico
new file mode 100644
index 000000000..ea084e3d7
Binary files /dev/null and b/public/favicon-DRC.ico differ
diff --git a/public/favicon-epa.ico b/public/favicon-epa.ico
new file mode 100644
index 000000000..1f337e469
Binary files /dev/null and b/public/favicon-epa.ico differ
diff --git a/public/favicon-gin.ico b/public/favicon-gin.ico
new file mode 100644
index 000000000..e74167870
Binary files /dev/null and b/public/favicon-gin.ico differ
diff --git a/public/manifest.json b/public/manifest.json
index 224109c11..5b1ab6ed2 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": "EPA National Biodiversity",
+ "name": "EPA National Biodiversity",
"icons": [
{
"src": "favicon.ico",
diff --git a/src/app.jsx b/src/app.jsx
index 98c93c711..451a0508b 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,10 @@ function AppLayout(props) {
);
case 'aoi':
return ;
+ case 'dashboard':
+ return ;
+ case 'dashboard-species':
+ return ;
default:
return isMobile ? : ;
}
diff --git a/src/assets/icons/analytics.svg b/src/assets/icons/analytics.svg
new file mode 100644
index 000000000..b9e077f5c
--- /dev/null
+++ b/src/assets/icons/analytics.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
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/bird_icon.svg b/src/assets/icons/bird_icon.svg
new file mode 100644
index 000000000..1c07a478c
--- /dev/null
+++ b/src/assets/icons/bird_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/amphibian_icon.svg b/src/assets/icons/dashboard/amphibian_icon.svg
new file mode 100644
index 000000000..a10e71db2
--- /dev/null
+++ b/src/assets/icons/dashboard/amphibian_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/ant_icon.svg b/src/assets/icons/dashboard/ant_icon.svg
new file mode 100644
index 000000000..36328d40f
--- /dev/null
+++ b/src/assets/icons/dashboard/ant_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/bird_icon.svg b/src/assets/icons/dashboard/bird_icon.svg
new file mode 100644
index 000000000..1c07a478c
--- /dev/null
+++ b/src/assets/icons/dashboard/bird_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/butterfly_icon.svg b/src/assets/icons/dashboard/butterfly_icon.svg
new file mode 100644
index 000000000..407c83dce
--- /dev/null
+++ b/src/assets/icons/dashboard/butterfly_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/mammal_icon.svg b/src/assets/icons/dashboard/mammal_icon.svg
new file mode 100644
index 000000000..2aae7479a
--- /dev/null
+++ b/src/assets/icons/dashboard/mammal_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/odonate_icon.svg b/src/assets/icons/dashboard/odonate_icon.svg
new file mode 100644
index 000000000..b1eeadfae
--- /dev/null
+++ b/src/assets/icons/dashboard/odonate_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/reptile_icon.svg b/src/assets/icons/dashboard/reptile_icon.svg
new file mode 100644
index 000000000..1e973c8fe
--- /dev/null
+++ b/src/assets/icons/dashboard/reptile_icon.svg
@@ -0,0 +1,4 @@
+
+
diff --git a/src/assets/icons/dashboard/tree_icon.svg b/src/assets/icons/dashboard/tree_icon.svg
new file mode 100644
index 000000000..ee09e8d3a
--- /dev/null
+++ b/src/assets/icons/dashboard/tree_icon.svg
@@ -0,0 +1,10 @@
+
+
diff --git a/src/assets/icons/duiker_icon_black.svg b/src/assets/icons/duiker_icon_black.svg
new file mode 100644
index 000000000..6c861129c
--- /dev/null
+++ b/src/assets/icons/duiker_icon_black.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/src/assets/icons/elephant.svg b/src/assets/icons/elephant.svg
new file mode 100644
index 000000000..6fb18bd88
--- /dev/null
+++ b/src/assets/icons/elephant.svg
@@ -0,0 +1,22 @@
+
+
+
+
diff --git a/src/assets/icons/gauge_icon.svg b/src/assets/icons/gauge_icon.svg
new file mode 100644
index 000000000..2a1aea659
--- /dev/null
+++ b/src/assets/icons/gauge_icon.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/src/assets/icons/house-solid.svg b/src/assets/icons/house-solid.svg
new file mode 100644
index 000000000..374579be5
--- /dev/null
+++ b/src/assets/icons/house-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/assets/icons/moon-regular.svg b/src/assets/icons/moon-regular.svg
new file mode 100644
index 000000000..112fb45d1
--- /dev/null
+++ b/src/assets/icons/moon-regular.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/okapi.svg b/src/assets/icons/okapi.svg
new file mode 100644
index 000000000..6def296bb
--- /dev/null
+++ b/src/assets/icons/okapi.svg
@@ -0,0 +1,23 @@
+
+
+
+
diff --git a/src/assets/icons/stacks.svg b/src/assets/icons/stacks.svg
new file mode 100644
index 000000000..964df48ed
--- /dev/null
+++ b/src/assets/icons/stacks.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/sun-regular.svg b/src/assets/icons/sun-regular.svg
new file mode 100644
index 000000000..16a9efbfa
--- /dev/null
+++ b/src/assets/icons/sun-regular.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/timeline.svg b/src/assets/icons/timeline.svg
new file mode 100644
index 000000000..9dfe6fae4
--- /dev/null
+++ b/src/assets/icons/timeline.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/assets/icons/user_icon.svg b/src/assets/icons/user_icon.svg
new file mode 100644
index 000000000..ed18bd6b2
--- /dev/null
+++ b/src/assets/icons/user_icon.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/assets/images/Choeropsis-liberiensis.jpeg b/src/assets/images/Choeropsis-liberiensis.jpeg
new file mode 100644
index 000000000..27c7c4cf8
Binary files /dev/null and b/src/assets/images/Choeropsis-liberiensis.jpeg differ
diff --git a/src/assets/images/Grey-winged_Robin-Chat_imported_from_iNaturalist_photo_4170503_on_23_February_2024.jpg b/src/assets/images/Grey-winged_Robin-Chat_imported_from_iNaturalist_photo_4170503_on_23_February_2024.jpg
new file mode 100644
index 000000000..f88cac4ed
Binary files /dev/null and b/src/assets/images/Grey-winged_Robin-Chat_imported_from_iNaturalist_photo_4170503_on_23_February_2024.jpg differ
diff --git a/src/assets/images/amphibians.svg b/src/assets/images/amphibians.svg
new file mode 100644
index 000000000..f1d96422e
--- /dev/null
+++ b/src/assets/images/amphibians.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/apalis.jpg b/src/assets/images/apalis.jpg
new file mode 100644
index 000000000..79fa244ec
Binary files /dev/null and b/src/assets/images/apalis.jpg differ
diff --git a/src/assets/images/birds.svg b/src/assets/images/birds.svg
new file mode 100644
index 000000000..d1656aa4f
--- /dev/null
+++ b/src/assets/images/birds.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/dashboard/Chiromantis_rufescens.jpg b/src/assets/images/dashboard/Chiromantis_rufescens.jpg
new file mode 100644
index 000000000..357e6dfd6
Binary files /dev/null and b/src/assets/images/dashboard/Chiromantis_rufescens.jpg differ
diff --git a/src/assets/images/dashboard/Congolacerta_vauereselli_hendrick_hinkel.jpg b/src/assets/images/dashboard/Congolacerta_vauereselli_hendrick_hinkel.jpg
new file mode 100644
index 000000000..d47032ed2
Binary files /dev/null and b/src/assets/images/dashboard/Congolacerta_vauereselli_hendrick_hinkel.jpg differ
diff --git a/src/assets/images/dashboard/Hyperolius_castaneus.jpg b/src/assets/images/dashboard/Hyperolius_castaneus.jpg
new file mode 100644
index 000000000..3fffeef64
Binary files /dev/null and b/src/assets/images/dashboard/Hyperolius_castaneus.jpg differ
diff --git a/src/assets/images/dashboard/Hyperolius_tuberculatus_brian_gratwicke.jpg b/src/assets/images/dashboard/Hyperolius_tuberculatus_brian_gratwicke.jpg
new file mode 100644
index 000000000..23c1e2dd4
Binary files /dev/null and b/src/assets/images/dashboard/Hyperolius_tuberculatus_brian_gratwicke.jpg differ
diff --git a/src/assets/images/dashboard/Leptopelis_christyi_gauvain_saucy.jpeg b/src/assets/images/dashboard/Leptopelis_christyi_gauvain_saucy.jpeg
new file mode 100644
index 000000000..a6d2fb2c2
Binary files /dev/null and b/src/assets/images/dashboard/Leptopelis_christyi_gauvain_saucy.jpeg differ
diff --git a/src/assets/images/dashboard/Myotis_bocagii.jpg b/src/assets/images/dashboard/Myotis_bocagii.jpg
new file mode 100644
index 000000000..0d77381a8
Binary files /dev/null and b/src/assets/images/dashboard/Myotis_bocagii.jpg differ
diff --git a/src/assets/images/dashboard/amphibian_icon_black.png b/src/assets/images/dashboard/amphibian_icon_black.png
new file mode 100644
index 000000000..6ef11cfba
Binary files /dev/null and b/src/assets/images/dashboard/amphibian_icon_black.png differ
diff --git a/src/assets/images/dashboard/amphibian_icon_white.png b/src/assets/images/dashboard/amphibian_icon_white.png
new file mode 100644
index 000000000..c6e23d6e3
Binary files /dev/null and b/src/assets/images/dashboard/amphibian_icon_white.png differ
diff --git a/src/assets/images/dashboard/ant_icon_black.png b/src/assets/images/dashboard/ant_icon_black.png
new file mode 100644
index 000000000..3728d5151
Binary files /dev/null and b/src/assets/images/dashboard/ant_icon_black.png differ
diff --git a/src/assets/images/dashboard/ant_icon_white.png b/src/assets/images/dashboard/ant_icon_white.png
new file mode 100644
index 000000000..6144ab2c7
Binary files /dev/null and b/src/assets/images/dashboard/ant_icon_white.png differ
diff --git a/src/assets/images/dashboard/bird_icon_black.png b/src/assets/images/dashboard/bird_icon_black.png
new file mode 100644
index 000000000..5c7d1bbf7
Binary files /dev/null and b/src/assets/images/dashboard/bird_icon_black.png differ
diff --git a/src/assets/images/dashboard/bird_icon_white.png b/src/assets/images/dashboard/bird_icon_white.png
new file mode 100644
index 000000000..a4f1a023c
Binary files /dev/null and b/src/assets/images/dashboard/bird_icon_white.png differ
diff --git a/src/assets/images/dashboard/bonobo.jpg b/src/assets/images/dashboard/bonobo.jpg
new file mode 100644
index 000000000..87d8a1122
Binary files /dev/null and b/src/assets/images/dashboard/bonobo.jpg differ
diff --git a/src/assets/images/dashboard/butterfly_icon_black.png b/src/assets/images/dashboard/butterfly_icon_black.png
new file mode 100644
index 000000000..3a3364f2f
Binary files /dev/null and b/src/assets/images/dashboard/butterfly_icon_black.png differ
diff --git a/src/assets/images/dashboard/butterfly_icon_white.png b/src/assets/images/dashboard/butterfly_icon_white.png
new file mode 100644
index 000000000..72a7a0f14
Binary files /dev/null and b/src/assets/images/dashboard/butterfly_icon_white.png differ
diff --git a/src/assets/images/dashboard/mammal_icon_black.png b/src/assets/images/dashboard/mammal_icon_black.png
new file mode 100644
index 000000000..f0c215775
Binary files /dev/null and b/src/assets/images/dashboard/mammal_icon_black.png differ
diff --git a/src/assets/images/dashboard/mammal_icon_white.png b/src/assets/images/dashboard/mammal_icon_white.png
new file mode 100644
index 000000000..eec9652a5
Binary files /dev/null and b/src/assets/images/dashboard/mammal_icon_white.png differ
diff --git a/src/assets/images/dashboard/odonate_icon_black.png b/src/assets/images/dashboard/odonate_icon_black.png
new file mode 100644
index 000000000..9e0ccb2e4
Binary files /dev/null and b/src/assets/images/dashboard/odonate_icon_black.png differ
diff --git a/src/assets/images/dashboard/odonate_icon_white.png b/src/assets/images/dashboard/odonate_icon_white.png
new file mode 100644
index 000000000..93741ef69
Binary files /dev/null and b/src/assets/images/dashboard/odonate_icon_white.png differ
diff --git a/src/assets/images/dashboard/okapi.jpg b/src/assets/images/dashboard/okapi.jpg
new file mode 100644
index 000000000..06c00aeca
Binary files /dev/null and b/src/assets/images/dashboard/okapi.jpg differ
diff --git a/src/assets/images/dashboard/peacock.jpg b/src/assets/images/dashboard/peacock.jpg
new file mode 100644
index 000000000..fd6f794c7
Binary files /dev/null and b/src/assets/images/dashboard/peacock.jpg differ
diff --git a/src/assets/images/dashboard/reptile_icon_black.png b/src/assets/images/dashboard/reptile_icon_black.png
new file mode 100644
index 000000000..ae47e0ed4
Binary files /dev/null and b/src/assets/images/dashboard/reptile_icon_black.png differ
diff --git a/src/assets/images/dashboard/reptile_icon_white.png b/src/assets/images/dashboard/reptile_icon_white.png
new file mode 100644
index 000000000..1746e4490
Binary files /dev/null and b/src/assets/images/dashboard/reptile_icon_white.png differ
diff --git a/src/assets/images/dashboard/shi_legend.png b/src/assets/images/dashboard/shi_legend.png
new file mode 100644
index 000000000..505454233
Binary files /dev/null and b/src/assets/images/dashboard/shi_legend.png differ
diff --git a/src/assets/images/dashboard/spi_legend.png b/src/assets/images/dashboard/spi_legend.png
new file mode 100644
index 000000000..c8c82785e
Binary files /dev/null and b/src/assets/images/dashboard/spi_legend.png differ
diff --git a/src/assets/images/dashboard/tree_icon_white.png b/src/assets/images/dashboard/tree_icon_white.png
new file mode 100644
index 000000000..dc94df978
Binary files /dev/null and b/src/assets/images/dashboard/tree_icon_white.png differ
diff --git a/src/assets/images/dashboard/viper.jpg b/src/assets/images/dashboard/viper.jpg
new file mode 100644
index 000000000..0e9897e71
Binary files /dev/null and b/src/assets/images/dashboard/viper.jpg differ
diff --git a/src/assets/images/drc_metrics_logos.jpg b/src/assets/images/drc_metrics_logos.jpg
new file mode 100644
index 000000000..6557d81dc
Binary files /dev/null and b/src/assets/images/drc_metrics_logos.jpg differ
diff --git a/src/assets/images/drc_region_logos.jpg b/src/assets/images/drc_region_logos.jpg
new file mode 100644
index 000000000..ec46529f9
Binary files /dev/null and b/src/assets/images/drc_region_logos.jpg differ
diff --git a/src/assets/images/egg.jpeg b/src/assets/images/egg.jpeg
new file mode 100644
index 000000000..785b141ff
Binary files /dev/null and b/src/assets/images/egg.jpeg differ
diff --git a/src/assets/images/frog.jpg b/src/assets/images/frog.jpg
new file mode 100644
index 000000000..f8da5cb46
Binary files /dev/null and b/src/assets/images/frog.jpg differ
diff --git a/src/assets/images/hyperolius.jpg b/src/assets/images/hyperolius.jpg
new file mode 100644
index 000000000..6b0806564
Binary files /dev/null and b/src/assets/images/hyperolius.jpg differ
diff --git a/src/assets/images/lophocebus.jpg b/src/assets/images/lophocebus.jpg
new file mode 100644
index 000000000..af0592d30
Binary files /dev/null and b/src/assets/images/lophocebus.jpg differ
diff --git a/src/assets/images/mammals.svg b/src/assets/images/mammals.svg
new file mode 100644
index 000000000..a28016c83
--- /dev/null
+++ b/src/assets/images/mammals.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/okapi_Derek_Keats_Flickr_CC-BY-2_0.jpg b/src/assets/images/okapi_Derek_Keats_Flickr_CC-BY-2_0.jpg
new file mode 100644
index 000000000..a5faf3ce7
Binary files /dev/null and b/src/assets/images/okapi_Derek_Keats_Flickr_CC-BY-2_0.jpg differ
diff --git a/src/assets/images/pilio.jpg b/src/assets/images/pilio.jpg
new file mode 100644
index 000000000..31b022903
Binary files /dev/null and b/src/assets/images/pilio.jpg differ
diff --git a/src/assets/images/reptiles.svg b/src/assets/images/reptiles.svg
new file mode 100644
index 000000000..974b0bc49
--- /dev/null
+++ b/src/assets/images/reptiles.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/assets/images/streak-throated.jpg b/src/assets/images/streak-throated.jpg
new file mode 100644
index 000000000..20652752e
Binary files /dev/null and b/src/assets/images/streak-throated.jpg differ
diff --git a/src/assets/images/trioceros.jpg b/src/assets/images/trioceros.jpg
new file mode 100644
index 000000000..f437ad7a9
Binary files /dev/null and b/src/assets/images/trioceros.jpg differ
diff --git a/src/assets/images/zebra-duiker.jpg b/src/assets/images/zebra-duiker.jpg
new file mode 100644
index 000000000..fa4cd4da1
Binary files /dev/null and b/src/assets/images/zebra-duiker.jpg differ
diff --git a/src/assets/logos/Guyana_PAC.png b/src/assets/logos/Guyana_PAC.png
new file mode 100644
index 000000000..d4d7bfaa5
Binary files /dev/null and b/src/assets/logos/Guyana_PAC.png differ
diff --git a/src/assets/logos/SL_flag.png b/src/assets/logos/SL_flag.png
new file mode 100644
index 000000000..983a7e1a0
Binary files /dev/null and b/src/assets/logos/SL_flag.png differ
diff --git a/src/assets/logos/epa_logo_transparent.png b/src/assets/logos/epa_logo_transparent.png
new file mode 100644
index 000000000..33bdee320
Binary files /dev/null and b/src/assets/logos/epa_logo_transparent.png differ
diff --git a/src/assets/logos/favicon-drc.ico b/src/assets/logos/favicon-drc.ico
new file mode 100644
index 000000000..ea084e3d7
Binary files /dev/null and b/src/assets/logos/favicon-drc.ico differ
diff --git a/src/assets/logos/favicon-epa.ico b/src/assets/logos/favicon-epa.ico
new file mode 100644
index 000000000..1f337e469
Binary files /dev/null and b/src/assets/logos/favicon-epa.ico differ
diff --git a/src/assets/logos/favicon-sle.ico b/src/assets/logos/favicon-sle.ico
new file mode 100644
index 000000000..f95b719ba
Binary files /dev/null and b/src/assets/logos/favicon-sle.ico differ
diff --git a/src/assets/logos/guinea.jpeg b/src/assets/logos/guinea.jpeg
new file mode 100644
index 000000000..b07f78848
Binary files /dev/null and b/src/assets/logos/guinea.jpeg differ
diff --git a/src/assets/logos/guinea.png b/src/assets/logos/guinea.png
new file mode 100644
index 000000000..0cc51e0c1
Binary files /dev/null and b/src/assets/logos/guinea.png differ
diff --git a/src/assets/logos/institut-congolais.png b/src/assets/logos/institut-congolais.png
new file mode 100644
index 000000000..325d35d8d
Binary files /dev/null and b/src/assets/logos/institut-congolais.png differ
diff --git a/src/components/charts/distribution-chart/distribution-chart-component.jsx b/src/components/charts/distribution-chart/distribution-chart-component.jsx
new file mode 100644
index 000000000..6cb40a4ae
--- /dev/null
+++ b/src/components/charts/distribution-chart/distribution-chart-component.jsx
@@ -0,0 +1,21 @@
+/* eslint-disable camelcase */
+import React from 'react';
+import { Bar } from 'react-chartjs-2';
+
+import styles from './distribution-chart-styles.module.scss';
+
+function DistributionsChartComponent(props) {
+ const { options, data } = props;
+
+ return (
+
+ {data && (
+
+
+
+ )}
+
+ );
+}
+
+export default DistributionsChartComponent;
diff --git a/src/components/charts/distribution-chart/distribution-chart-styles.module.scss b/src/components/charts/distribution-chart/distribution-chart-styles.module.scss
new file mode 100644
index 000000000..915d90677
--- /dev/null
+++ b/src/components/charts/distribution-chart/distribution-chart-styles.module.scss
@@ -0,0 +1,28 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.container{
+ display: flex;
+ flex-direction: column;
+ padding: 10px 5px 10px 26px;
+ flex-grow: 1;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+
+ .title{
+ color: $white;
+ font-family: $font-family-1;
+ font-size: $font-size-sm;
+ font-style: normal;
+ font-weight: 700;
+ line-height: normal;
+ text-transform: uppercase;
+ }
+
+ .chart{
+ width: 100%;
+ }
+}
diff --git a/src/components/charts/distribution-chart/index.js b/src/components/charts/distribution-chart/index.js
new file mode 100644
index 000000000..2a8b8c479
--- /dev/null
+++ b/src/components/charts/distribution-chart/index.js
@@ -0,0 +1,3 @@
+import Component from './distribution-chart-component';
+
+export default Component;
diff --git a/src/components/charts/spi-arc-chart/index.js b/src/components/charts/spi-arc-chart/index.js
new file mode 100644
index 000000000..8db701c31
--- /dev/null
+++ b/src/components/charts/spi-arc-chart/index.js
@@ -0,0 +1,3 @@
+import Component from './spi-arc-chart-component';
+
+export default Component;
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
new file mode 100644
index 000000000..fe07c320e
--- /dev/null
+++ b/src/components/charts/spi-arc-chart/spi-arc-chart-component.jsx
@@ -0,0 +1,109 @@
+import React, { useContext, useEffect, useState } from 'react';
+import { Doughnut } from 'react-chartjs-2';
+
+import { useT } from '@transifex/react';
+
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ ArcElement,
+ Title,
+ Tooltip,
+ Legend,
+} from 'chart.js';
+import cx from 'classnames';
+
+import { LightModeContext } from '../../../context/light-mode';
+
+import styles from './spi-arc-chart-styles.module.scss';
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ ArcElement,
+ Title,
+ Tooltip,
+ Legend
+);
+
+function SpiArcChartComponent(props) {
+ const t = useT();
+ const { scores, width, height, data, img, species, value, isPercent } = props;
+ const { lightMode } = useContext(LightModeContext);
+ const [score, setScore] = useState(0);
+
+ const doughnutOptions = {
+ cutout: '80%',
+ radius: '100%',
+ rotation: -90,
+ responsive: false,
+ circumference: 180,
+ hoverOffset: 5,
+ animation: {
+ animateRotate: true,
+ animateScale: false,
+ },
+ plugins: {
+ legend: {
+ display: false,
+ },
+ },
+ layout: {
+ padding: {
+ left: 5,
+ right: 5,
+ top: 5,
+ bottom: 5,
+ },
+ },
+ };
+
+ const arcChartHeight = height || 100;
+ const arcChartWidth = width || 120;
+
+ const getPercentage = () => {
+ const { count, total } = scores[species];
+
+ if (!value) {
+ const percent = (count / total) * 100 || 0;
+ return [percent, 100 - percent];
+ }
+ return [count, 100 - count];
+ };
+
+ const getScore = () => {
+ if (!isPercent) return score;
+ return `${score}%`;
+ };
+
+ useEffect(() => {
+ if (!value) return;
+ setScore(value.toFixed(1));
+ }, [value]);
+
+ return (
+
+ {scores && (
+
{getPercentage()[0].toFixed(1)}
+ )}
+
+ {scores && (
+
+
+
+ {scores[species].total} {t(species)}
+
+
+ )}
+ {!scores &&
{getScore()}
}
+
+ );
+}
+
+export default SpiArcChartComponent;
diff --git a/src/components/charts/spi-arc-chart/spi-arc-chart-styles.module.scss b/src/components/charts/spi-arc-chart/spi-arc-chart-styles.module.scss
new file mode 100644
index 000000000..c7b527503
--- /dev/null
+++ b/src/components/charts/spi-arc-chart/spi-arc-chart-styles.module.scss
@@ -0,0 +1,63 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.spi{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ --font-color: #{$white};
+
+ &.light{
+ --font-color: #{$black};
+ }
+
+ .score{
+ color: var(--font-color);
+ text-align: center;
+ font-family: $font-family-1;
+ font-size: $font-size-tick;
+ font-style: normal;
+ font-weight: 700;
+ line-height: normal;
+ margin-bottom: -20px;
+ }
+
+ .globalScore{
+ color: var(--font-color);
+ text-align: center;
+ font-family: $font-family-1;
+ font-size: $font-size-tick;
+ font-style: normal;
+ font-weight: 700;
+ line-height: normal;
+ margin-top: -35px;
+ }
+
+ .taxoGroup{
+ display: flex;
+ flex-direction: column;
+ margin-top: -60px;
+ align-items: center;
+
+ .richness{
+ color: var(--font-color);
+ text-align: center;
+ font-family: $font-family-1;
+ font-size: $font-size-xxs;
+ font-style: italic;
+ font-weight: 400;
+ line-height: normal;
+ }
+
+ .score{
+ font-size: $font-size-base;
+ font-weight: 600;
+ text-transform: uppercase;
+ margin-bottom: 0;
+ }
+ }
+}
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..f4b12c2fc
--- /dev/null
+++ b/src/components/dashboard-login/dashboard-login-component.jsx
@@ -0,0 +1,80 @@
+import React, { useEffect } from 'react';
+
+import { useT } from '@transifex/react';
+
+import IdentityManager from '@arcgis/core/identity/IdentityManager';
+import OAuthInfo from '@arcgis/core/identity/OAuthInfo';
+import Portal from '@arcgis/core/portal/Portal';
+
+import Button from 'components/button';
+
+import styles from './dashboard-login-styles.module.scss';
+
+const { ARCGIS_OAUTH_APP_ID } = import.meta.env;
+
+const info = new OAuthInfo({
+ appId: ARCGIS_OAUTH_APP_ID,
+ popup: false,
+});
+
+function DashboardLoginComponent(props) {
+ const { setLoggedIn, setUser } = props;
+ const t = useT();
+
+ const handleLogin = () => {
+ IdentityManager.getCredential(info.portalUrl);
+ };
+
+ const handleLoginSuccess = () => {
+ const portal = new Portal();
+ portal.authMode = 'immediate';
+ portal.load().then(() => {
+ setLoggedIn(true);
+ setUser(portal.user);
+ });
+ };
+
+ useEffect(() => {
+ IdentityManager.registerOAuthInfos([info]);
+
+ IdentityManager.checkSignInStatus(info.portalUrl)
+ .then(handleLoginSuccess)
+ .catch((error) => {
+ throw Error(error);
+ });
+ }, []);
+
+ 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..855982715
--- /dev/null
+++ b/src/components/dashboard-login/dashboard-login-styles.module.scss
@@ -0,0 +1,35 @@
+@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;
+ 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..fbacfa624
--- /dev/null
+++ b/src/components/dashboard-login/index.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+import DashboardLoginComponent from './dashboard-login-component';
+
+function DashboardLogin(props) {
+ return ;
+}
+
+export default DashboardLogin;
diff --git a/src/components/dashboard-nav/dashboard-nav-component.jsx b/src/components/dashboard-nav/dashboard-nav-component.jsx
new file mode 100644
index 000000000..4b93c9302
--- /dev/null
+++ b/src/components/dashboard-nav/dashboard-nav-component.jsx
@@ -0,0 +1,123 @@
+import React, { useContext } from 'react';
+
+import { useT } from '@transifex/react';
+
+import SouthAmericaIcon from '@mui/icons-material/SouthAmerica';
+import cx from 'classnames';
+import { LightModeContext } from 'context/light-mode';
+
+import { NAVIGATION } from 'constants/dashboard-constants.js';
+
+import BirdsIcon from 'icons/bird_icon.svg?react';
+import SpeciesIcon from 'icons/gauge_icon.svg?react';
+import HomeIcon from 'icons/house-solid.svg?react';
+import StacksIcon from 'icons/stacks.svg?react';
+import TimeLineIcon from 'icons/timeline.svg?react';
+
+import styles from './dashboard-nav-styles.module.scss';
+
+function DashboardNavComponent(props) {
+ const t = useT();
+ const { selectedIndex, setSelectedIndex, scientificName, countryISO } = props;
+ const { lightMode } = useContext(LightModeContext);
+
+ const titles = {
+ HOME: 'home',
+ REGIONS: 'regions',
+ DATA_LAYER: 'data-layer',
+ BIO_DIVERSITY: 'bio-diversity',
+ REGION_ANALYSIS: 'region-analysis',
+ TRENDS: 'trends',
+ };
+
+ const updateHistory = (page, title) => {
+ window.history.pushState({ selectedIndex: page }, '', ``);
+ setSelectedIndex(page);
+ };
+
+ return (
+
+
+
+
+
+ {selectedIndex >= NAVIGATION.SPECIES &&
+ selectedIndex <= NAVIGATION.REGION_ANALYSIS && (
+
+
+
+
+ )}
+
+
+
+ );
+}
+
+export default DashboardNavComponent;
diff --git a/src/components/dashboard-nav/dashboard-nav-styles.module.scss b/src/components/dashboard-nav/dashboard-nav-styles.module.scss
new file mode 100644
index 000000000..3be8c2563
--- /dev/null
+++ b/src/components/dashboard-nav/dashboard-nav-styles.module.scss
@@ -0,0 +1,75 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.sidenav{
+ --nav-button-bg: #{$white};
+ --svg-fill: #{$white};
+ --svg-selected-fill: #{$black};
+ --font-color: #{$white};
+ --border-color: #{$brand-color-main};
+ --save-button-text: #{$dark-text};
+ --border-color-hover: #{$brand-color-main-hover};
+
+ &.light{
+ --nav-button-bg: #{$black};
+ --svg-fill: #{$black};
+ --svg-selected-fill: #{$white};
+ --font-color: #{$black};
+ --border-color: #{$mol-blue};
+ --save-button-text: #{$white};
+ --border-color-hover: #{$mol-blue};
+ @include lightBackdropBlur();
+ border: none;
+ }
+
+ display: flex;
+ height: 100%;
+
+ .icons{
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ border-right: 1px solid var(--font-color);
+
+ .subNav{
+ display: flex;
+ flex-direction: column;
+ background-color: rgba(255, 255, 255, 0.5);
+ }
+
+ button{
+ width: 50px;
+ height: 50px;
+
+ svg{
+ width: 30px;
+ height: 30px;
+ fill: var(--svg-fill);
+
+ rect{
+ width: 50px;
+ }
+ }
+
+ &.selected,
+ &:hover{
+ background: var(--nav-button-bg);
+
+ svg{
+ fill: var(--svg-selected-fill);
+ }
+ }
+
+ &.disabled{
+ cursor: not-allowed;
+ background: transparent;
+
+ svg{
+ fill: var(--svg-fill);
+ }
+ }
+ }
+ }
+}
diff --git a/src/components/dashboard-nav/index.js b/src/components/dashboard-nav/index.js
new file mode 100644
index 000000000..2d444d5e8
--- /dev/null
+++ b/src/components/dashboard-nav/index.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import DashboardNavComponent from './dashboard-nav-component';
+
+function DashboardNav(props) {
+ return (
+
+ )
+}
+
+export default DashboardNav;
diff --git a/src/components/filters/filter-component-styles.module.scss b/src/components/filters/filter-component-styles.module.scss
new file mode 100644
index 000000000..174d15b27
--- /dev/null
+++ b/src/components/filters/filter-component-styles.module.scss
@@ -0,0 +1,55 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.filters {
+ width: 50%;
+
+ --font-color: #{$white};
+ --border-color: #{$brand-color-main};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$dark-text};
+ --border-color-hover: #{$brand-color-main-hover};
+ color: var(--font-color);
+
+ &.light{
+ --font-color: #{$black};
+ --border-color: #{$mol-blue};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$white};
+ --border-color-hover: #{$mol-blue};
+ }
+
+ .titleRow {
+ .title {
+ font-size: 18px;
+ font-weight: 700;
+ text-transform: uppercase;
+ }
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .close{
+ color: var(--font-color);
+ }
+
+ .filterList{
+ margin-bottom: 15px;
+
+ .filterGroupTitle {
+ font-size: 16px;
+ padding: 0 0 8px;
+ }
+
+ .filterbox {
+ padding-left: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: start;
+ gap: 10px;
+ }
+ }
+}
diff --git a/src/components/filters/filter-component.jsx b/src/components/filters/filter-component.jsx
new file mode 100644
index 000000000..973ed5eda
--- /dev/null
+++ b/src/components/filters/filter-component.jsx
@@ -0,0 +1,188 @@
+import React, { useContext, useEffect, useState } from 'react';
+
+import { useT } from '@transifex/react';
+
+import DoneIcon from '@mui/icons-material/Done';
+import { Chip } from '@mui/material';
+import cx from 'classnames';
+import { LightModeContext } from 'context/light-mode';
+import { Loading } from 'he-components';
+
+import Button from 'components/button';
+
+import hrTheme from 'styles/themes/hr-theme.module.scss';
+
+import styles from './filter-component-styles.module.scss';
+
+function FilterComponent(props) {
+ const t = useT();
+ const {
+ setFilteredTaxaList,
+ selectedTaxa,
+ taxaList,
+ filters,
+ setFilters,
+ isLoading,
+ updateActiveFilter,
+ } = props;
+
+ const [anyActive, setAnyActive] = useState(false);
+ const { lightMode } = useContext(LightModeContext);
+
+ const clearCounts = () => {
+ setFilteredTaxaList([]);
+ const updatedFilters = [...filters];
+ updatedFilters.forEach((f) => {
+ const innerFilter = f;
+ innerFilter.filters.forEach((ff) => {
+ const filter = ff;
+ filter.count = 0;
+ });
+ });
+
+ setFilters(updatedFilters);
+ };
+
+ const refreshCounts = () => {
+ clearCounts();
+
+ let allTaxa = taxaList;
+ if (selectedTaxa) {
+ allTaxa = allTaxa.filter((taxa) => taxa.taxa === selectedTaxa);
+ }
+
+ const filtered = [];
+ // allTaxa.species = [];
+ let isAnyActive = false;
+
+ filters.forEach((f) =>
+ f.filters.forEach((ff) => {
+ if (ff.active) isAnyActive = true;
+ })
+ );
+ // TODO: FIGURE OUT FILTERS
+ allTaxa.forEach((taxa) => {
+ // Object.values(allTaxa).forEach((taxa) => {
+ const candidateTaxa = { ...taxa };
+ const candidateSpecies = [];
+ taxa.species.forEach((species) => {
+ const speciesFilters = [];
+ const speciesOrFilters = [];
+ filters.forEach((filterGroup) => {
+ filterGroup.filters.forEach((filter) => {
+ const result = filter.test(species);
+ filter.result = result;
+ if (isAnyActive && filter.active) {
+ if (filter.type === 'and') {
+ speciesFilters.push(result);
+ } else if (filter.type === 'or') {
+ speciesOrFilters.push(result);
+ }
+ }
+ });
+ });
+ const allAnd =
+ speciesFilters.every((x) => x) && speciesFilters.length > 0;
+ const anyOr = speciesOrFilters.includes(true);
+ let inCandidate = false;
+ if (!isAnyActive) {
+ inCandidate = true;
+ candidateSpecies.push(species);
+ // only ands
+ } else if (allAnd && speciesOrFilters.length === 0) {
+ inCandidate = true;
+ candidateSpecies.push(species);
+ // only or's
+ } else if (speciesFilters.length === 0 && anyOr) {
+ inCandidate = true;
+ candidateSpecies.push(species);
+ } else if (allAnd && anyOr) {
+ inCandidate = true;
+ candidateSpecies.push(species);
+ }
+
+ const onAnd = allAnd || speciesFilters.length === 0;
+
+ filters.forEach((filterGroup) => {
+ filterGroup.filters.forEach((filter) => {
+ if (onAnd && filter.result) {
+ filter.count += 1;
+ }
+ });
+ });
+ });
+
+ candidateTaxa.species = candidateSpecies;
+ candidateTaxa.count = candidateSpecies.length;
+ filtered.push(candidateTaxa);
+ });
+
+ setAnyActive(isAnyActive);
+ setFilteredTaxaList(filtered);
+ };
+
+ const activateFilter = (filter) => {
+ updateActiveFilter(filter);
+ refreshCounts();
+ };
+
+ const clearFilters = () => {
+ filters.forEach((f) =>
+ f.filters.forEach((ff) => {
+ ff.active = false;
+ })
+ );
+ refreshCounts();
+ };
+
+ useEffect(() => {
+ if (!taxaList) return;
+ refreshCounts();
+ }, [taxaList]);
+
+ useEffect(() => {
+ refreshCounts();
+ }, [selectedTaxa]);
+
+ return (
+
+
+
{t('Filters')}
+ {anyActive && (
+
+ )}
+
+
+ {isLoading &&
}
+ {!isLoading &&
+ filters.map((filterGroup, index) => {
+ return (
+
+
+ {t(filterGroup.title)}
+
+
+ {filterGroup.filters.map((filter, idx) => {
+ return (
+ : ''}
+ color={filter.active ? 'success' : 'primary'}
+ label={`${t(filter.name)}: ${filter.count}`}
+ onClick={() => activateFilter(filter)}
+ />
+ );
+ })}
+
+
+ );
+ })}
+
+ );
+}
+
+export default FilterComponent;
diff --git a/src/components/filters/index.js b/src/components/filters/index.js
new file mode 100644
index 000000000..9a5225690
--- /dev/null
+++ b/src/components/filters/index.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+import FilterComponent from './filter-component';
+
+function FilterContainer(props) {
+ return ;
+}
+
+export default FilterContainer;
diff --git a/src/components/layer-toggle/index.js b/src/components/layer-toggle/index.js
index c72faeee9..4f9c5f25b 100644
--- a/src/components/layer-toggle/index.js
+++ b/src/components/layer-toggle/index.js
@@ -35,7 +35,7 @@ function LayerToggle(props) {
};
useEffect(() => {
- const _isChecked = activeLayers.some(
+ const _isChecked = activeLayers?.some(
(layer) => layer.title === option.value
);
setIsChecked(_isChecked);
diff --git a/src/components/map-view/component.jsx b/src/components/map-view/component.jsx
new file mode 100644
index 000000000..b820c631b
--- /dev/null
+++ b/src/components/map-view/component.jsx
@@ -0,0 +1,46 @@
+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,
+ spinner = true,
+ } = 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..5d10bd630
--- /dev/null
+++ b/src/components/map-view/index.js
@@ -0,0 +1,130 @@
+import React, { useEffect, useState } from 'react';
+import { connect } from 'react-redux';
+
+// import FeatureLayer from '@arcgis/core/layers/FeatureLayer';
+// import GraphicsLayer from '@arcgis/core/layers/GraphicsLayer';
+// import GroupLayer from '@arcgis/core/layers/GroupLayer';
+// import TileLayer from '@arcgis/core/layers/TileLayer';
+import { createDefaultDashboardLayers } from 'utils/dashboard-utils';
+
+import Map from '@arcgis/core/Map';
+import MapView from '@arcgis/core/views/MapView';
+
+// import { DASHBOARD_LAYER_SLUGS, DASHBOARD_URLS } from 'constants/dashboard';
+import { SATELLITE_BASEMAP_LAYER } from 'constants/layers-slugs';
+
+import Component from './component';
+import mapStateToProps from './selectors';
+
+function ViewContainer(props) {
+ const {
+ onMapLoad,
+ mapName,
+ mapId,
+ viewSettings,
+ map,
+ setMap,
+ view,
+ setView,
+ geometry,
+ } = props;
+
+ const [loadState, setLoadState] = useState('loading');
+ const [countryLayer, setCountryLayer] = useState(null);
+ const [graphicsLayer, setGraphicsLayer] = useState(null);
+ const [groupLayer, setGroupLayer] = useState(null);
+
+ 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,
+ center: [zoomGeometry.longitude - 15, zoomGeometry.latitude],
+ zoom: 5.5,
+ 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(() => {
+ const layers = createDefaultDashboardLayers();
+ setCountryLayer(layers.countries);
+ setGraphicsLayer(layers.graphics);
+ setGroupLayer(layers.group);
+
+ const flatMap = new Map({
+ basemap: SATELLITE_BASEMAP_LAYER,
+ ground: {
+ surfaceColor: '#070710',
+ },
+ layers: [layers.countries, layers.group],
+ });
+
+ setMap(flatMap);
+
+ if (onMapLoad) {
+ onMapLoad(flatMap);
+ }
+ }, []);
+
+ useEffect(() => {
+ if (map) {
+ const flatView = new MapView({
+ map,
+ container: `map-container-${mapName || mapId}`,
+ zoom: 6,
+ // popup: new Popup(),
+ ...viewSettings,
+ });
+
+ setView(flatView);
+ }
+ }, [map, viewSettings]);
+
+ useEffect(() => {
+ if (map && view) {
+ setLoadState('loaded');
+ }
+ }, [map, view]);
+
+ useEffect(() => {
+ if (view && geometry) {
+ const query = {
+ geometry,
+ returnGeometry: true,
+ outFields: ['*'],
+ };
+ highlightCountry(query, query.geometry, view);
+ }
+ }, [view, geometry]);
+
+ return ;
+}
+
+export default connect(mapStateToProps, null)(ViewContainer);
diff --git a/src/components/map-view/selectors.js b/src/components/map-view/selectors.js
new file mode 100644
index 000000000..d6f72cff1
--- /dev/null
+++ 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/components/partners/index.js b/src/components/partners/index.js
new file mode 100644
index 000000000..1e39226d4
--- /dev/null
+++ b/src/components/partners/index.js
@@ -0,0 +1,8 @@
+import React, { useEffect } from 'react';
+import PartnersComponent from './partners-component';
+
+function PartnersContainer() {
+ return ;
+}
+
+export default PartnersContainer;
diff --git a/src/components/partners/partner-styles.module.scss b/src/components/partners/partner-styles.module.scss
new file mode 100644
index 000000000..545f1c178
--- /dev/null
+++ b/src/components/partners/partner-styles.module.scss
@@ -0,0 +1,11 @@
+.partners{
+ display: flex;
+ gap: 25px;
+ align-self: flex-end;
+ margin: 0 10px 10px 0;
+
+ img{
+ height: 30px;
+ max-width: 100%;
+ }
+}
diff --git a/src/components/partners/partners-component.jsx b/src/components/partners/partners-component.jsx
new file mode 100644
index 000000000..e02106851
--- /dev/null
+++ b/src/components/partners/partners-component.jsx
@@ -0,0 +1,24 @@
+import React from 'react';
+
+import styles from './partner-styles.module.scss';
+
+import logoImgColor from 'logos/eowilson_logo_v3.svg';
+import heLogoImg from 'logos/he_logo_color_full.png?react';
+import iucnLogo from 'logos/iucn.png';
+import molLogo from 'logos/mol.png';
+import yaleLogo from 'logos/yale.png';
+
+function PartnersComponent() {
+ return (
+
+
+ )
+}
+
+export default PartnersComponent
diff --git a/src/components/protected-areas-table/protected-areas-table-styles.module.scss b/src/components/protected-areas-table/protected-areas-table-styles.module.scss
index 7f1443c8e..50cb6c855 100644
--- a/src/components/protected-areas-table/protected-areas-table-styles.module.scss
+++ b/src/components/protected-areas-table/protected-areas-table-styles.module.scss
@@ -12,7 +12,7 @@
border-bottom: solid 1px $firefly;
th, td {
- text-align: left;
+ text-align: center;
}
td {
@@ -23,6 +23,7 @@
.headerColumnContainer {
display: flex;
align-items: center;
+ justify-content: center;
}
.arrowsContainer {
diff --git a/src/components/species-group-title/index.js b/src/components/species-group-title/index.js
new file mode 100644
index 000000000..58d478baf
--- /dev/null
+++ b/src/components/species-group-title/index.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import SpeciesGroupTitleComponent from './species-group-title-component'
+
+function SpeciesGroupTitleContainer(props) {
+ return (
+
+ )
+}
+
+export default SpeciesGroupTitleContainer
diff --git a/src/components/species-group-title/species-group-title-component.jsx b/src/components/species-group-title/species-group-title-component.jsx
new file mode 100644
index 000000000..a6a815bb6
--- /dev/null
+++ b/src/components/species-group-title/species-group-title-component.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+
+import cx from 'classnames';
+
+import styles from './species-group-title-component.module.scss';
+
+function SpeciesGroupTitleComponent(props) {
+ const { species } = props;
+ const { scientific_name, common_name } = species;
+ return (
+
+
+ {species === '__blank' ? '' : common_name}
+
+
{scientific_name}
+
+ );
+}
+
+export default SpeciesGroupTitleComponent;
diff --git a/src/components/species-group-title/species-group-title-component.module.scss b/src/components/species-group-title/species-group-title-component.module.scss
new file mode 100644
index 000000000..ed9d00519
--- /dev/null
+++ b/src/components/species-group-title/species-group-title-component.module.scss
@@ -0,0 +1,34 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.familyTitle {
+
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+ border-bottom: 1px solid var(--font-color);
+ padding-bottom: 3px;
+ margin-left: 10px;
+ margin-right: 10px;
+
+ .sci {
+ padding-left: 10px;
+ }
+}
+.listBox {
+ min-height: calc(100% - 170px);
+}
+.name {
+ .sci {
+ font-weight: 300;
+ font-size: $font-size-sm;
+ font-style: italic;
+ }
+ .common {
+ font-size: $font-size-sm;
+ font-weight: 500;
+ }
+}
diff --git a/src/components/species-group/index.js b/src/components/species-group/index.js
new file mode 100644
index 000000000..a2fad39e0
--- /dev/null
+++ b/src/components/species-group/index.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import SpeciesGroupComponent from './species-group-component'
+
+function SpeciesGroupContainer(props) {
+ return (
+
+ )
+}
+
+export default SpeciesGroupContainer
diff --git a/src/components/species-group/species-group-component.jsx b/src/components/species-group/species-group-component.jsx
new file mode 100644
index 000000000..7133840ea
--- /dev/null
+++ b/src/components/species-group/species-group-component.jsx
@@ -0,0 +1,56 @@
+import React, { useContext } from 'react';
+
+import cx from 'classnames';
+import { LightModeContext } from 'context/light-mode';
+
+import {
+ NAVIGATION,
+ SPECIES_SELECTED_COOKIE,
+ SPECIES_IMAGE_URL,
+} from 'constants/dashboard-constants.js';
+
+import TaxaImageComponent from '../taxa-image';
+
+import styles from './species-group-component.module.scss';
+
+function SpeciesGroupComponent(props) {
+ const { species, selectedTaxaObj, setSelectedIndex, setScientificName } =
+ props;
+ // eslint-disable-next-line camelcase
+ const { species_url, common_name, scientific_name } = species;
+ const { lightMode } = useContext(LightModeContext);
+
+ const selectSpecies = (selectedSpecies) => {
+ setSelectedIndex(NAVIGATION.DATA_LAYER);
+ setScientificName(selectedSpecies.scientific_name);
+ localStorage.setItem(
+ SPECIES_SELECTED_COOKIE,
+ selectedSpecies.scientific_name
+ );
+ };
+
+ return (
+
+ );
+}
+
+export default SpeciesGroupComponent;
diff --git a/src/components/species-group/species-group-component.module.scss b/src/components/species-group/species-group-component.module.scss
new file mode 100644
index 000000000..152ea49f6
--- /dev/null
+++ b/src/components/species-group/species-group-component.module.scss
@@ -0,0 +1,72 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+
+.speciesBox {
+ --font-color: #{$white};
+ --border-color: #{$brand-color-main};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$dark-text};
+ --border-color-hover: #{$brand-color-main-hover};
+ color: var(--font-color);
+
+ &.light{
+ --font-color: #{$black};
+ --border-color: #{$mol-blue};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$white};
+ --border-color-hover: #{$mol-blue};
+ }
+
+ display: flex;
+ flex-direction: row;
+ padding: 0;
+ font-family: $font-family-1;
+ font-size: $font-size-base;
+ color: var(--font-color);
+ width: 100%;
+
+ svg{
+ fill: var(--font-color);
+ width: 30px;
+ height: 30px;
+ }
+
+ .name {
+ padding: 5px 10px;
+ }
+
+ cursor: pointer;
+ .imgBox {
+ width: 32px;
+ max-width: 32px;
+ min-width: 32px;
+ padding: 3px;
+ text-align: center;
+ overflow: hidden;
+ object-fit: cover;
+ }
+ img {
+ max-width: 32px;
+ min-width: 32px;
+ margin: 0 auto;
+ height: 32px;
+ border-radius: 2px;
+ }
+ .speciesText {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ text-align: left;
+ font-size: $font-size-sm;
+ color: var(--font-color);
+ }
+ .openDataset {
+ text-decoration: underline;
+ font-size: $font-size-sm;
+ }
+}
+
+
diff --git a/src/components/species-list/index.js b/src/components/species-list/index.js
new file mode 100644
index 000000000..c984dc9a0
--- /dev/null
+++ b/src/components/species-list/index.js
@@ -0,0 +1,9 @@
+import React from 'react';
+
+import SpeciesListComponent from './species-list-component';
+
+function SpeciesListContainer(props) {
+ return ;
+}
+
+export default SpeciesListContainer;
diff --git a/src/components/species-list/species-list-component-styles.module.scss b/src/components/species-list/species-list-component-styles.module.scss
new file mode 100644
index 000000000..7115a32c5
--- /dev/null
+++ b/src/components/species-list/species-list-component-styles.module.scss
@@ -0,0 +1,191 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.filters {
+ width: 50%;
+
+ --font-color: #{$white};
+ --border-color: #{$brand-color-main};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$dark-text};
+ --border-color-hover: #{$brand-color-main-hover};
+ color: var(--font-color);
+
+ &.light{
+ --font-color: #{$black};
+ --border-color: #{$mol-blue};
+ --selected-font-color: #{$white};
+ --save-button-text: #{$white};
+ --border-color-hover: #{$mol-blue};
+ }
+
+ .titleRow {
+ .title {
+ font-size: $font-size-tick;
+ font-weight: 700;
+ }
+
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ }
+
+ .close{
+ color: var(--font-color);
+ }
+
+ .filterGroupTitle {
+ font-size: $font-size-base;
+ padding: 15px 0 8px;
+ }
+
+ .filterbox {
+ padding-left: 10px;
+ display: flex;
+ flex-direction: column;
+ align-items: start;
+ gap: 10px;
+ }
+}
+
+.titleRow {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 10px;
+
+ .title {
+ font-size: $font-size-tick;
+ font-weight: 700;
+ text-transform: uppercase;
+ cursor: default;
+ }
+}
+
+.taxaList {
+ max-width: 400px;
+ margin-top: 15px;
+ display: flex;
+ flex-direction: column;
+ gap: 5px;
+
+ svg{
+ fill: var(--font-color);
+ width: 30px;
+ height: 30px;
+ }
+}
+
+.thumb {
+ height: 32px;
+ width: 32px;
+}
+.title {
+ cursor: pointer;
+ padding: 0 5px;
+}
+
+.spinner {
+ max-height: 32px;
+}
+.datasetList {
+ max-width: 250px;
+ display: flex;
+ flex-direction: column;
+ color: var(--font-color);
+ a:hover,
+ a:focus {
+ background-color: unset;
+ color: var(--font-color);
+ }
+ img {
+ margin: 2px !important;
+ height: 25px !important;
+ max-width: 25px !important;
+ }
+}
+.title {
+ font-size: $font-size-base;
+ display: flex;
+ flex-direction: row;
+ justify-content: flex-start;
+ align-items: center;
+ color: var(--font-color);
+ font-family: $font-family-1;
+
+ .header {
+ padding-left: 7px;
+ }
+}
+
+.filterCount {
+ margin-left: auto;
+ text-align: right;
+ margin-right: 15px;
+ font-size: $font-size-xs;
+}
+
+.speciesList {
+ padding-top: 5px;
+ height: calc(100vh - 280px);
+ overflow-y: hidden;
+ width: 250px;
+
+ .filterResults {
+ margin-top: 8px;
+ overflow-y: auto;
+ max-height: calc(100vh - 315px);
+ }
+
+ .search{
+ border: 1px solid var(--border-color);
+ padding: 5px;
+ border-radius: 8px;
+ flex-grow: 1;
+ background: #{$white};
+ width: 225px;
+ margin: 5px 0;
+
+ input[type="text"]{
+ color: var(--border-color);
+ width: 100%;
+ }
+
+ ::placeholder{
+ color: var(--border-color);
+ }
+
+ svg{
+ fill: var(--border-color);
+ color: var(--border-color);
+
+ path{
+ fill: var(--border-color);
+ color: var(--border-color);
+ }
+ }
+
+ &.showResults{
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ }
+ }
+
+ .speciesFilter {
+ padding: 10px 0;
+ line-height: 32px;
+ justify-content: center;
+ input {
+ width: 90%;
+ line-height: 32px;
+ margin-left: 2.5%;
+ }
+ }
+
+ .close {
+ margin: 10px 15px 10px 10px;
+ }
+}
+
diff --git a/src/components/species-list/species-list-component.jsx b/src/components/species-list/species-list-component.jsx
new file mode 100644
index 000000000..d33640ea0
--- /dev/null
+++ b/src/components/species-list/species-list-component.jsx
@@ -0,0 +1,293 @@
+import React, { useContext, useEffect, useState } from 'react';
+
+import { useT } from '@transifex/react';
+
+import cx from 'classnames';
+import { LightModeContext } from 'context/light-mode';
+import { Loading } from 'he-components';
+
+import Button from 'components/button';
+import SearchInput from 'components/search-input';
+
+import hrTheme from 'styles/themes/hr-theme.module.scss';
+
+import SpeciesGroupContainer from '../species-group';
+// import SpeciesGroupTitleContainer from '../species-group-title';
+
+import TaxaImageComponent from '../taxa-image';
+
+import styles from './species-list-component-styles.module.scss';
+
+function SpeciesListComponent(props) {
+ const t = useT();
+ const { selectedTaxa, setSelectedTaxa, filteredTaxaList, isLoading } = props;
+
+ const { lightMode } = useContext(LightModeContext);
+ const SPHINGID_MOTHS = /Sphingid moths/gi;
+
+ const [inFilter, setInFilter] = useState(0);
+ const [familyCounts, setFamilyCounts] = useState({});
+ const [selectedTaxaObj, setSelectedTaxaObj] = useState();
+ const [filteredSpecies, setFilteredSpecies] = useState({});
+ const [filter, setFilter] = useState();
+
+ const getTaxaTitle = (label, taxa) => {
+ const taxaToCheck = [
+ 'MAMMALS',
+ 'BIRDS',
+ 'REPTILES',
+ 'AMPHIBIANS',
+ 'CONIFERS',
+ 'CACTI',
+ 'PALMS',
+ 'OTHER PLANTS*', // because the backend sends a * already
+ ];
+ if (taxa) {
+ if (taxa.match(SPHINGID_MOTHS)) {
+ return `Old World ${label}*`;
+ }
+ if (!taxaToCheck.includes(taxa.toUpperCase())) {
+ return `${t(label)}*`;
+ }
+ }
+
+ return t(label);
+ };
+
+ const updateSelectedTaxa = (taxa) => {
+ if (!taxa) return;
+
+ setFilter('');
+ setSelectedTaxa(taxa);
+ const fc = {};
+
+ const sto = filteredTaxaList?.find((t) => t.taxa === taxa);
+ if (sto === undefined) return;
+
+ setInFilter(sto?.species?.length);
+
+ const transformer = (sp) => ({
+ ...sp,
+ visible: true,
+ filterString: [sp.scientificname, sp.common, sp.family, sp.family_common]
+ .join(' ')
+ .toLocaleLowerCase(),
+ });
+ const transformed = [];
+ sto?.species?.forEach((sp) => {
+ let species = sp;
+ if (!fc[species.family]) {
+ fc[species.family] = {
+ total: 1,
+ visibleCount: 0,
+ };
+ species.first = true;
+ } else {
+ species.first = false;
+ fc[species.family].total += 1;
+ }
+ species = transformer(species);
+ species.familyObj = fc[species.family];
+ transformed.push(species);
+ });
+ sto.species = transformed;
+ setFamilyCounts(fc);
+ setSelectedTaxaObj(sto);
+ };
+
+ const applyFilter = () => {
+ // this.virtualScroll?.scrollToIndex(0);
+ const inFilterCheck = (sp) => sp.common_name?.indexOf(filter) > -1;
+ setInFilter(0);
+
+ // clear the counts
+ const fc = familyCounts;
+ Object.keys(fc).forEach((k) => {
+ fc[k].visibleCount = 0;
+ });
+
+ // sort by family common
+ const familySortedSpecies = sortFilteredSpecies(selectedTaxaObj?.species);
+
+ // group by family common
+ let groupByFamily = familySortedSpecies?.reduce((group, result) => {
+ const catName = result.scientific_name[0] ?? '__blank';
+
+ const updateResult = { ...result };
+
+ updateResult.visible = inFilterCheck(result);
+ if (updateResult.visible) {
+ let inf = inFilter;
+ setInFilter(inf++);
+ fc[updateResult.family].visibleCount += 1;
+
+ group[catName] = group[catName] ?? [];
+ group[catName].push(updateResult);
+ }
+
+ setFamilyCounts(fc);
+ return group;
+ }, {});
+
+ if (groupByFamily) {
+ // sort family common by common
+ const groupKeys = Object.keys(groupByFamily);
+
+ groupKeys.forEach((groupKey) => {
+ groupByFamily[groupKey].sort((a, b) => {
+ if (a.scientificname < b.scientificname) {
+ return -1;
+ }
+ if (a.scientificname > b.scientificname) {
+ return 1;
+ }
+ return 0;
+ });
+ });
+
+ const keyLength = Object.keys(groupByFamily).length - 1;
+
+ // check if there is a group with no name
+ if (Object.keys(groupByFamily)[keyLength] === '') {
+ const noNameGroup = Object.values(groupByFamily)[keyLength];
+ delete groupByFamily[Object.keys(groupByFamily)[keyLength]];
+ groupByFamily = { ...groupByFamily, __blank: noNameGroup };
+ }
+
+ setFilteredSpecies(groupByFamily);
+ } else {
+ setFilteredSpecies({});
+ }
+ };
+
+ const handleSearch = (event) => {
+ setFilter(event.currentTarget.value.toLowerCase().trim());
+ };
+
+ const clearSelection = () => {
+ setSelectedTaxa('');
+ };
+
+ const sortFilteredSpecies = (species) => {
+ return species?.sort((a, b) => {
+ if (a.scientific_name < b.scientific_name) {
+ return -1;
+ }
+ if (a.scientific_name > b.scientific_name) {
+ return 1;
+ }
+ return 0;
+ });
+ };
+
+ useEffect(() => {
+ if (!selectedTaxa) return;
+ updateSelectedTaxa(selectedTaxa);
+ }, [selectedTaxa, filteredTaxaList]);
+
+ useEffect(() => {
+ if (!selectedTaxaObj) return;
+
+ applyFilter();
+ }, [selectedTaxaObj]);
+
+ useEffect(() => {
+ const handler = setTimeout(() => {
+ applyFilter();
+ }, 300);
+
+ return () => {
+ clearTimeout(handler);
+ };
+ }, [filter]);
+
+ return (
+
+
+
{t('Species')}
+ {selectedTaxa && (
+
+ )}
+
+
+
+ {!selectedTaxa &&
+ filteredTaxaList?.map((taxa, index) => {
+ return (
+
+ );
+ })}
+
+ {isLoading &&
}
+ {!isLoading && selectedTaxa && selectedTaxaObj && (
+
+
+ {selectedTaxaObj?.count}
+
+ {getTaxaTitle(selectedTaxaObj?.title, selectedTaxaObj?.taxa)}
+
+
+
+
+ {Object.keys(filteredSpecies).map((sp, index) => {
+ return (
+
+ {/* {filteredSpecies[sp].length > 0 && (
+
+ )} */}
+ {filteredSpecies[sp].map(
+ (v, idx) =>
+ v.visible && (
+
+ )
+ )}
+
+ );
+ })}
+
+
+ )}
+
+ );
+}
+export default SpeciesListComponent;
diff --git a/src/components/species-richness/index.js b/src/components/species-richness/index.js
new file mode 100644
index 000000000..f6a16c2e1
--- /dev/null
+++ b/src/components/species-richness/index.js
@@ -0,0 +1,3 @@
+import Component from './species-richness-component';
+
+export default Component;
diff --git a/src/components/species-richness/species-richness-component.jsx b/src/components/species-richness/species-richness-component.jsx
new file mode 100644
index 000000000..f4ca05006
--- /dev/null
+++ b/src/components/species-richness/species-richness-component.jsx
@@ -0,0 +1,235 @@
+import React, { useContext, useEffect, useState } from 'react';
+
+import { useT } from '@transifex/react';
+
+import { getCSSVariable } from 'utils/css-utils';
+
+import {
+ Chart as ChartJS,
+ CategoryScale,
+ LinearScale,
+ ArcElement,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend,
+} from 'chart.js';
+import cx from 'classnames';
+import last from 'lodash/last';
+
+import AmphibiansBlack from 'images/dashboard/amphibian_icon_black.png?react';
+import AmphibiansWhite from 'images/dashboard/amphibian_icon_white.png?react';
+import BirdsBlack from 'images/dashboard/bird_icon_black.png?react';
+import BirdsWhite from 'images/dashboard/bird_icon_white.png?react';
+import MammalsBlack from 'images/dashboard/mammal_icon_black.png?react';
+import MammalsWhite from 'images/dashboard/mammal_icon_white.png?react';
+import ReptilesBlack from 'images/dashboard/reptile_icon_black.png?react';
+import ReptilesWhite from 'images/dashboard/reptile_icon_white.png?react';
+
+import {
+ NATIONAL_TREND,
+ PROVINCE_TREND,
+} from '../../containers/sidebars/dashboard-trends-sidebar/dashboard-trends-sidebar-component';
+import compStyles from '../../containers/sidebars/dashboard-trends-sidebar/spi/score-distibutions/score-distributions-spi-styles.module.scss';
+import { LightModeContext } from '../../context/light-mode';
+import SpiArcChartComponent from '../charts/spi-arc-chart/spi-arc-chart-component';
+
+import styles from './species-richness-styles.module.scss';
+
+ChartJS.register(
+ CategoryScale,
+ LinearScale,
+ ArcElement,
+ BarElement,
+ Title,
+ Tooltip,
+ Legend
+);
+
+function SpeciesRichnessComponent(props) {
+ const t = useT();
+ const { selectedProvince, activeTrend, provinces, countryData } = props;
+
+ const { lightMode } = useContext(LightModeContext);
+ const [scores, setScores] = useState({
+ birds: {
+ count: 0,
+ total: 0,
+ percentage: 0,
+ },
+ mammals: {
+ count: 0,
+ total: 0,
+ percentage: 0,
+ },
+ reptiles: {
+ count: 0,
+ total: 0,
+ percentage: 0,
+ },
+ amphibians: {
+ count: 0,
+ total: 0,
+ percentage: 0,
+ },
+ });
+
+ const [titleText, setTitleText] = useState(
+ `NATIONAL ${t(' SPI BY TAXONOMIC GROUP')}`
+ );
+
+ const getPercentage = (species) => {
+ const { count } = scores[species];
+ return [count, 100 - count];
+ };
+
+ const getScores = () => {
+ let data = [];
+ if (selectedProvince && activeTrend === PROVINCE_TREND) {
+ const regionData = provinces.find(
+ (region) => region.region_name === selectedProvince.region_name
+ );
+ data = regionData;
+ } else {
+ data = last(countryData);
+ }
+
+ if (data) {
+ const {
+ BirdSpeciesRichness,
+ BirdSPI,
+ MammalSpeciesRichness,
+ MammalSPI,
+ ReptileSpeciesRichness,
+ ReptileSPI,
+ AmphibianSpeciesRichness,
+ AmphibianSPI,
+ } = data;
+
+ setScores({
+ birds: {
+ count: BirdSPI,
+ total: BirdSpeciesRichness,
+ },
+ mammals: {
+ count: MammalSPI,
+ total: MammalSpeciesRichness,
+ },
+ reptiles: {
+ count: ReptileSPI,
+ total: ReptileSpeciesRichness,
+ },
+ amphibians: {
+ count: AmphibianSPI,
+ total: AmphibianSpeciesRichness,
+ },
+ });
+ }
+ };
+
+ useEffect(() => {
+ if (!selectedProvince) return;
+ getScores();
+ if (activeTrend === NATIONAL_TREND || !selectedProvince) {
+ setTitleText(`NATIONAL ${t(' SPI BY TAXONOMIC GROUP')}`);
+ } else if (activeTrend === PROVINCE_TREND && selectedProvince) {
+ setTitleText(
+ `${selectedProvince?.region_name} ${t('SPI BY TAXONOMIC GROUP')}`
+ );
+ }
+ }, [selectedProvince, activeTrend]);
+
+ const emptyArcColor = lightMode
+ ? getCSSVariable('dark-opacity')
+ : getCSSVariable('white-opacity-20');
+
+ const birdData = {
+ labels: [t('Birds'), t('Remaining')],
+ datasets: [
+ {
+ label: '',
+ data: getPercentage('birds'),
+ backgroundColor: [getCSSVariable('birds'), emptyArcColor],
+ borderColor: [getCSSVariable('birds'), emptyArcColor],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ const mammalsData = {
+ labels: [t('Mammals'), t('Remaining')],
+ datasets: [
+ {
+ label: '',
+ data: getPercentage('mammals'),
+ backgroundColor: [getCSSVariable('mammals'), emptyArcColor],
+ borderColor: [getCSSVariable('mammals'), emptyArcColor],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ const reptilesData = {
+ labels: [t('Reptiles'), t('Remaining')],
+ datasets: [
+ {
+ label: '',
+ data: getPercentage('reptiles'),
+ backgroundColor: [getCSSVariable('reptiles'), emptyArcColor],
+ borderColor: [getCSSVariable('reptiles'), emptyArcColor],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ const amphibianData = {
+ labels: [t('Amphibians'), t('Remaining')],
+ datasets: [
+ {
+ label: '',
+ data: getPercentage('amphibians'),
+ backgroundColor: [getCSSVariable('amphibians'), emptyArcColor],
+ borderColor: [getCSSVariable('amphibians'), emptyArcColor],
+ borderWidth: 1,
+ },
+ ],
+ };
+
+ return (
+
+
{titleText}
+
+
+
+
+
+
+
+ );
+}
+
+export default SpeciesRichnessComponent;
diff --git a/src/components/species-richness/species-richness-styles.module.scss b/src/components/species-richness/species-richness-styles.module.scss
new file mode 100644
index 000000000..989f60345
--- /dev/null
+++ b/src/components/species-richness/species-richness-styles.module.scss
@@ -0,0 +1,76 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.container{
+ display: flex;
+ flex-direction: column;
+ padding: 10px 5px 10px 26px;
+ flex-grow: 1;
+ align-items: center;
+ gap: 8px;
+ width: 100%;
+
+ --font-color: #{$white};
+ --border-color: #{$brand-color-main};
+
+ &.light{
+ --font-color: #{$black};
+ --border-color: #{$mol-blue};
+ }
+
+ .spis{
+ display: flex;
+ gap: 10px;
+ align-items: center;
+ width: 100%;
+ justify-content: center;
+ border-radius: 5px;
+ border: 1.5px solid var(--border-color);
+ box-shadow: -2px 4px 4px 0px rgba(0, 0, 0, 0.25);
+ padding: 15px 0;
+
+ .spi{
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+
+ .score{
+ color: var(--font-color);
+ text-align: center;
+ font-family: "Open Sans";
+ font-size: 20px;
+ font-style: normal;
+ font-weight: 700;
+ line-height: normal;
+ margin-bottom: -20px;
+ }
+
+ .taxoGroup{
+ display: flex;
+ flex-direction: column;
+ margin-top: -60px;
+ align-items: center;
+
+ .richness{
+ color: var(--font-color);
+ text-align: center;
+ font-family: "Open Sans";
+ font-size: 11px;
+ font-style: italic;
+ font-weight: 400;
+ line-height: normal;
+ }
+
+ .score{
+ font-size: 16px;
+ font-weight: 600;
+ text-transform: uppercase;
+ margin-bottom: 0;
+ }
+ }
+ }
+ }
+}
diff --git a/src/components/taxa-image/index.js b/src/components/taxa-image/index.js
new file mode 100644
index 000000000..daa94abd0
--- /dev/null
+++ b/src/components/taxa-image/index.js
@@ -0,0 +1,50 @@
+import React from 'react';
+
+import AmphibiansIcon from 'icons/dashboard/amphibian_icon.svg?react';
+import AntIcon from 'icons/dashboard/ant_icon.svg?react';
+import BirdsIcon from 'icons/dashboard/bird_icon.svg?react';
+import ButterFlyIcon from 'icons/dashboard/butterfly_icon.svg?react';
+import MammalsIcon from 'icons/dashboard/mammal_icon.svg?react';
+import OdoanteIcon from 'icons/dashboard/odonate_icon.svg?react';
+import ReptilesImage from 'icons/dashboard/reptile_icon.svg?react';
+import TreeIcon from 'icons/dashboard/tree_icon.svg?react';
+
+function TaxaImageComponent(props) {
+ const { taxa } = props;
+
+ const getTaxaIcon = () => {
+ let icon = '';
+ switch (taxa) {
+ case 'amphibians':
+ icon = ;
+ break;
+ case 'ants':
+ icon = ;
+ break;
+ case 'birds':
+ icon = ;
+ break;
+ case 'butterflies':
+ icon = ;
+ break;
+ case 'mammals':
+ icon = ;
+ break;
+ case 'odonates':
+ icon = ;
+ break;
+ case 'reptiles':
+ icon = ;
+ break;
+ case 'trees':
+ icon = ;
+ break;
+ default:
+ break;
+ }
+ return icon;
+ };
+ return <>{getTaxaIcon()}>;
+}
+
+export default TaxaImageComponent;
diff --git a/src/components/top-menu/index.js b/src/components/top-menu/index.js
new file mode 100644
index 000000000..a65f92eed
--- /dev/null
+++ b/src/components/top-menu/index.js
@@ -0,0 +1,10 @@
+import React from 'react'
+import TopMenuComponent from './top-menu-component';
+
+function TopMenuContainer(props) {
+ return (
+
+ )
+}
+
+export default TopMenuContainer;
diff --git a/src/components/top-menu/top-menu-component.jsx b/src/components/top-menu/top-menu-component.jsx
new file mode 100644
index 000000000..19e083aba
--- /dev/null
+++ b/src/components/top-menu/top-menu-component.jsx
@@ -0,0 +1,46 @@
+import React from 'react';
+
+import { useT } from '@transifex/react';
+
+import IdentityManager from '@arcgis/core/identity/IdentityManager';
+
+import UserAvatar from 'icons/user_icon.svg?react';
+
+import styles from './top-menu-styles.module.scss';
+
+function UserProfile(props) {
+ const t = useT();
+ const { setLoggedIn } = props;
+ const logOut = () => {
+ IdentityManager.destroyCredentials();
+ setLoggedIn(false);
+ };
+ return (
+ <>
+
+
+
+ |
+
+ >
+ );
+}
+
+function TopMenuComponent(props) {
+ const { user } = props;
+ return (
+ // {user && }
+
+
+
+ );
+}
+
+export default TopMenuComponent;
diff --git a/src/components/top-menu/top-menu-styles.module.scss b/src/components/top-menu/top-menu-styles.module.scss
new file mode 100644
index 000000000..0ce7c745c
--- /dev/null
+++ b/src/components/top-menu/top-menu-styles.module.scss
@@ -0,0 +1,56 @@
+@import 'styles/ui.module';
+@import 'styles/settings';
+@import 'styles/typography-extends';
+@import 'styles/common-animations.module';
+
+.container{
+ --font-color: #{$white};
+ --bg-color: #{$brand-color-main};
+
+ &.light{
+ --font-color: #{$black};
+ --bg-color: #{$white};
+ }
+
+ position: absolute;
+ top: 0;
+ right: 50px;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ background-color: var(--bg-color);
+ padding: 4px 10px;
+ border-bottom-right-radius: 8px;
+ border-bottom-left-radius: 8px;
+ border-color: var(--font-color);
+ border-width: 1px;
+ border-style: solid;
+ border-top: none;
+ color: var(--font-color);
+
+ a{
+ color: var(--font-color);
+ text-decoration: none;
+ font-weight: 700;
+
+ &.profile{
+ height: 30px;
+ }
+
+ svg{
+ width: 20px;
+ height: 30px;
+ fill: var(--font-color);
+
+ rect{
+ width: 50px;
+ }
+ }
+ }
+
+ button{
+ color: var(--font-color);
+ font-weight: 700;
+ font-size: 16px;
+ }
+}
diff --git a/src/constants/dashboard-constants.js b/src/constants/dashboard-constants.js
new file mode 100644
index 000000000..2635fd1f4
--- /dev/null
+++ b/src/constants/dashboard-constants.js
@@ -0,0 +1,66 @@
+export const LAYER_TITLE_TYPES = {
+ EXPERT_RANGE_MAPS: 'EXPERT RANGE MAPS',
+ POINT_OBSERVATIONS: 'POINT OBSERVATIONS',
+ REGIONAL_CHECKLISTS: 'REGIONAL CHECKLISTS',
+ TREND: 'TREND',
+};
+
+export const DASHBOARD_LAYER_SLUGS = {
+ INITIAL_COUNTRY_LAYER: 'INITIAL_COUNTRY_LAYER',
+ INITIAL_GROUP_LAYER: 'INITIAL_GROUP_LAYER',
+};
+
+export const INITIAL_LAYERS = [
+ DASHBOARD_LAYER_SLUGS.INITIAL_COUNTRY_LAYER,
+ DASHBOARD_LAYER_SLUGS.INITIAL_GROUP_LAYER,
+ 'cities_labels_layer',
+ 'regions_labels_layer',
+ 'countries_labels_layer',
+ 'landscape_features_labels_layer',
+ 'admin_areas_feature_layer',
+];
+
+export const REGION_OPTIONS = {
+ PROVINCES: 'PROVINCES',
+ PROTECTED_AREAS: 'PROTECTED_AREAS',
+ FORESTS: 'FORESTS',
+ DRAW: 'DRAW',
+};
+
+export const SPI_LATEST_YEAR = 2024;
+export const SHI_LATEST_YEAR = 2021;
+export const SHI_TREND_LATEST_YEAR = 2022;
+export const SII_LATEST_YEAR = 2023;
+
+export const SPECIES_SELECTED_COOKIE = 'species_selected';
+
+export const NAVIGATION = {
+ HOME: 1,
+ REGION: 2,
+ SPECIES: 3,
+ DATA_LAYER: 4,
+ BIO_IND: 5,
+ REGION_ANALYSIS: 6,
+ TRENDS: 7,
+ EXPLORE_SPECIES: 8,
+};
+
+export const LAYER_OPTIONS = {
+ PROTECTED_AREAS: 'PROTECTED_AREAS',
+ PROPOSED_PROTECTED_AREAS: 'PROPOSED_PROTECTED_AREAS',
+ PROVINCES: 'PROVINCES',
+ PROVINCES_VECTOR: 'PROVINCES_VECTOR',
+ PROVINCES_REGION_VECTOR: 'PROVINCES_REGION_VECTOR',
+ PRIORITY_AREAS: 'PRIORITY_AREAS',
+ COMMUNITY_FORESTS: 'COMMUNITY_FORESTS',
+ HABITAT: 'HABITAT',
+ FORESTS: 'FORESTS',
+ POINT_OBSERVATIONS: 'POINT_OBSERVATIONS',
+ ADMINISTRATIVE_LAYERS: 'ADMINISTRATIVE_LAYERS',
+ EXPERT_RANGE_MAPS: 'EXPERT_RANGE_MAPS',
+};
+
+export const TAXA_IMAGE_URL = 'icons/dashboard/';
+
+export const SPECIES_IMAGE_URL =
+ 'https://storage.googleapis.com/mol-assets2/thumbs/';
diff --git a/src/constants/layers-urls.js b/src/constants/layers-urls.js
index f303895dd..6d4423cea 100644
--- a/src/constants/layers-urls.js
+++ b/src/constants/layers-urls.js
@@ -461,3 +461,50 @@ export const LAYERS_URLS = {
[SPECIFIC_REGIONS_WDPA_LAYER]:
'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/SpecificRegions_wdpa_202401/FeatureServer/0',
};
+
+export const DASHBOARD_URLS = {
+ INITIAL_COUNTRY_LAYER: '53a1e68de7e4499cad77c80daba46a94',
+ COUNTRY_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/ESRI_table1_v2_0/FeatureServer',
+ SPECIES_OCCURENCE_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/regional_species_COD/FeatureServer',
+ WDPA_OCCURENCE_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/cd_occ_province_join/FeatureServer',
+ SPI_PROVINCE_TREND_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/ESRI_table2_v2_2/FeatureServer',
+ SPI_REGION_SPECIES_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/regional_species_spi_scores_year_2024_v1_2/FeatureServer',
+ SPI_HISTOGRAM_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/regional_and_national_spi_bin_count_2024/FeatureServer',
+ SHI_PROVINCE_TREND_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/drc_provinces_spi_join2/FeatureServer',
+ SHI_SPECIES_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/national_species_shi_scores_year_2024/FeatureServer',
+ SHI_HISTOGRAM_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/shs_summary_for_stacked_bar_chart_2021/FeatureServer',
+ SHI_PROVINCE_HISTOGRAM_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/regional_shs_bin_count_2022/FeatureServer',
+ SHI_PROVINCE_SPECIES_URL:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/regional_species_shs_scores_year_2022/FeatureServer',
+ AMPHIBIAN_LOOKUP:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/taxa_amphibians_final/FeatureServer',
+ BIRDS_LOOKUP:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/taxa_birds_final/FeatureServer',
+ MAMMALS_LOOKUP:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/taxa_mammals_final/FeatureServer',
+ REPTILES_LOOKUP:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/taxa_reptiles_final/FeatureServer',
+ PRECALC_AOI:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/gadm1_precalculated_aoi_summaries_updated_20240321/FeatureServer',
+ WDPA: 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/wdpa_occ_species_COD/FeatureServer',
+ WDPA_PRECALC:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/wdpa_precalculated_aoi_summaries_updated_20240408/FeatureServer',
+ ADMIN_AREAS_FEATURE_LAYER: [
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/gadm0_aoi_summaries_updated_20240326/FeatureServer',
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/gadm1_precalculated_aoi_summaries_updated_20240321/FeatureServer',
+ ],
+ FOREST:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/forest_title_refined_range_species/FeatureServer',
+ PRIORITY_SPECIES:
+ 'https://services9.arcgis.com/IkktFdUAcY3WrH25/arcgis/rest/services/priority_species/FeatureServer',
+};
diff --git a/src/containers/menus/globes-menu/component.jsx b/src/containers/menus/globes-menu/component.jsx
index 4f5ed8cb5..80fb83f8a 100644
--- a/src/containers/menus/globes-menu/component.jsx
+++ b/src/containers/menus/globes-menu/component.jsx
@@ -75,7 +75,7 @@ GlobesMenu.propTypes = {
GlobesMenu.defaultProps = {
className: '',
landing: false,
- onMouseLeave: () => {},
+ onMouseLeave: () => { },
};
export default GlobesMenu;
diff --git a/src/containers/menus/sidemenu/component.jsx b/src/containers/menus/sidemenu/component.jsx
index faa5db028..f21b37d1c 100644
--- a/src/containers/menus/sidemenu/component.jsx
+++ b/src/containers/menus/sidemenu/component.jsx
@@ -45,7 +45,6 @@ function SideMenu({
className={styles.searchBtn}
handleClick={() => setSearcherOpen(true)}
/>
-
{isSearcherOpen && (
)}
-
-