diff --git a/src/components/CustomWorldMap.cy.js b/src/components/CustomWorldMap.cy.js
index d90aa047..76559ffd 100644
--- a/src/components/CustomWorldMap.cy.js
+++ b/src/components/CustomWorldMap.cy.js
@@ -1,8 +1,15 @@
+import { mountWithTheme as mount } from 'models/test-utils';
import CustomWorldMap from './CustomWorldMap';
-import { mountWithTheme as mount } from '../models/test-utils';
describe('CustomWorldMap', () => {
it('renders', () => {
mount();
});
+
+ it('shows 0 instead of NaN for missing tree counts', () => {
+ mount();
+
+ cy.contains('0').should('exist');
+ cy.contains('NaN').should('not.exist');
+ });
});
diff --git a/src/components/CustomWorldMap.js b/src/components/CustomWorldMap.js
index a6b37bc6..64b6ae9f 100644
--- a/src/components/CustomWorldMap.js
+++ b/src/components/CustomWorldMap.js
@@ -3,10 +3,10 @@ import Box from '@mui/material/Box';
import Typography from '@mui/material/Typography';
import React from 'react';
import WorldMap from 'react-world-map';
+import { useMobile } from 'hooks/globalHooks';
+import TreeTooltip from 'images/tree_tooltip.svg';
import { makeStyles } from 'models/makeStyles';
import { abbreviateNumber } from 'models/utils';
-import { useMobile } from '../hooks/globalHooks';
-import TreeTooltip from '../images/tree_tooltip.svg';
const useStyles = makeStyles()((theme) => ({
root: {
@@ -66,6 +66,9 @@ const mapContinentName = (continentName) => {
function ToolTip({ totalTrees, con }) {
const { classes } = useStyles();
const isMobile = useMobile();
+ const safeTotalTrees = Number.isFinite(Number(totalTrees))
+ ? Number(totalTrees)
+ : 0;
return (
- {totalTrees}
+ {abbreviateNumber(safeTotalTrees)}
);
@@ -114,7 +117,7 @@ function CustomWorldMap({ totalTrees, con }) {
{continentAbr.map((cont, ind) => (
diff --git a/src/models/utils.js b/src/models/utils.js
index 3e2652c0..6b30f6bc 100644
--- a/src/models/utils.js
+++ b/src/models/utils.js
@@ -228,8 +228,14 @@ function nextPathBaseDecode(path, base) {
const wrapper = (callback) => (params) =>
callback(params).catch((e) => {
log.warn('error retrieving server props:', e);
- if (e.response?.status === 404) return { notFound: true };
+ if (e.response?.status === 404) {
+ return {
+ notFound: true,
+ revalidate: Number(process.env.NEXT_CACHE_REVALIDATION_OVERRIDE) || 30,
+ };
+ }
return {
+ notFound: true,
revalidate: Number(process.env.NEXT_CACHE_REVALIDATION_OVERRIDE) || 30,
};
});
diff --git a/src/pages/organizations/[organizationid].js b/src/pages/organizations/[organizationid].js
index bf7bd1ce..b6bd40ec 100644
--- a/src/pages/organizations/[organizationid].js
+++ b/src/pages/organizations/[organizationid].js
@@ -65,17 +65,43 @@ export default function Organization(props) {
// manipulate the map
const { map } = mapContext;
if (map && organization) {
- // map.flyTo(tree.lat, tree.lon, 16);
- await map.setFilters({
- map_name: organization.map_name,
- });
- const bounds = pathResolver.getBounds(router);
- if (bounds) {
- log.warn('goto bounds found in url');
- await map.gotoBounds(bounds);
- } else {
- const view = await map.getInitialView();
- await map.gotoView(view.center.lat, view.center.lon, view.zoomLevel);
+ try {
+ // map.flyTo(tree.lat, tree.lon, 16);
+ await map.setFilters({
+ map_name: organization.map_name,
+ });
+ const bounds = pathResolver.getBounds(router);
+ if (bounds) {
+ log.warn('goto bounds found in url');
+ await map.gotoBounds(bounds);
+ } else {
+ try {
+ const view = await map.getInitialView();
+ if (view?.center) {
+ await map.gotoView(
+ view.center.lat,
+ view.center.lon,
+ view.zoomLevel,
+ );
+ } else {
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
+ } catch (err) {
+ log.warn(
+ 'getInitialView failed, falling back to global view',
+ err,
+ );
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
+ }
+ } catch (err) {
+ log.warn('organization page map sync failed', err);
}
} else {
log.warn('no data:', map, organization);
diff --git a/src/pages/planters/[planterid].js b/src/pages/planters/[planterid].js
index 457161fb..0af9e849 100644
--- a/src/pages/planters/[planterid].js
+++ b/src/pages/planters/[planterid].js
@@ -78,7 +78,11 @@ export default function Planter(props) {
log.warn('props for planter page:', props);
const { planter, nextExtraIsEmbed } = props;
- const { featuredTrees } = planter;
+ const featuredTrees = planter.featuredTrees || { trees: [], total: 0 };
+ const associatedOrganizations = planter.associatedOrganizations || {
+ organizations: [],
+ };
+ const planterSpecies = planter.species || { species: [] };
const treeCount = featuredTrees?.total;
const mapContext = useMapContext();
const isMobile = useMobile();
@@ -114,17 +118,43 @@ export default function Planter(props) {
// manipulate the map
const { map } = mapContext;
if (map && planter) {
- // map.flyTo(tree.lat, tree.lon, 16);
- await map.setFilters({
- userid: planter.id,
- });
- const bounds = pathResolver.getBounds(router);
- if (bounds) {
- log.warn('goto bounds found in url');
- await map.gotoBounds(bounds);
- } else {
- const view = await map.getInitialView();
- map.gotoView(view.center.lat, view.center.lon, view.zoomLevel);
+ try {
+ // map.flyTo(tree.lat, tree.lon, 16);
+ await map.setFilters({
+ userid: planter.id,
+ });
+ const bounds = pathResolver.getBounds(router);
+ if (bounds) {
+ log.warn('goto bounds found in url');
+ await map.gotoBounds(bounds);
+ } else {
+ try {
+ const view = await map.getInitialView();
+ if (view?.center) {
+ await map.gotoView(
+ view.center.lat,
+ view.center.lon,
+ view.zoomLevel,
+ );
+ } else {
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
+ } catch (err) {
+ log.warn(
+ 'getInitialView failed, falling back to global view',
+ err,
+ );
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
+ }
+ } catch (err) {
+ log.warn('planter page map sync failed', err);
}
}
}
@@ -344,7 +374,7 @@ export default function Planter(props) {
Featured trees by {planter.first_name}
`/planters/${planter.id}/trees/${item.id}`}
/>
@@ -377,7 +407,7 @@ export default function Planter(props) {
setIsPlanterTab(false)
: undefined
}
@@ -391,7 +421,7 @@ export default function Planter(props) {
}}
title="Associated Orgs"
text={
- planter.associatedOrganizations.organizations.length || (
+ associatedOrganizations.organizations.length || (
- {planter.species.species.map((species) => (
+ {planterSpecies.species.map((species) => (
))}
- {(!planter.species.species ||
- planter.species.species.length === 0) && (
+ {planterSpecies.species.length === 0 && (
NO DATA YET
)}
@@ -456,7 +485,7 @@ export default function Planter(props) {
display: !isPlanterTab ? 'block' : 'none',
}}
>
- {planter.associatedOrganizations.organizations.map((org) => (
+ {associatedOrganizations.organizations.map((org) => (
<>
)}
@@ -594,8 +615,8 @@ export default function Tree({
buttonText="Meet the Planter"
cardImageSrc={planter?.image_url || imagePlaceholder}
rotation={planter?.image_rotation}
- link={`/planters/${planter.id}?keyword=${nextExtraKeyword}${
- isEmbed ? '&embed=true' : ''
+ link={`/planters/${planter.id}${
+ extraQuery ? `?${extraQuery}` : ''
}`}
/>
diff --git a/src/pages/wallets/[walletid].js b/src/pages/wallets/[walletid].js
index eb63b9b0..87ab8e2c 100644
--- a/src/pages/wallets/[walletid].js
+++ b/src/pages/wallets/[walletid].js
@@ -75,22 +75,47 @@ export default function Wallet(props) {
// manipulate the map
const { map } = mapContext;
if (map && wallet) {
- // map.flyTo(tree.lat, tree.lon, 16);
- log.warn('set filter for wallet');
- await map.setFilters({
- wallet: wallet.name,
- });
- const bounds = pathResolver.getBounds(router);
- if (bounds) {
- log.warn('goto bounds found in url');
- await map.gotoBounds(bounds);
- } else {
- const view = await map.getInitialView();
-
- if (view.zoomLevel < 2) {
- view.zoomLevel = 2;
+ try {
+ // map.flyTo(tree.lat, tree.lon, 16);
+ log.warn('set filter for wallet');
+ await map.setFilters({
+ wallet: wallet.name,
+ });
+ const bounds = pathResolver.getBounds(router);
+ if (bounds) {
+ log.warn('goto bounds found in url');
+ await map.gotoBounds(bounds);
+ } else {
+ try {
+ const view = await map.getInitialView();
+ if (view?.center) {
+ if (view.zoomLevel < 2) {
+ view.zoomLevel = 2;
+ }
+ await map.gotoView(
+ view.center.lat,
+ view.center.lon,
+ view.zoomLevel,
+ );
+ } else {
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
+ } catch (err) {
+ log.warn(
+ 'getInitialView failed, falling back to global view',
+ err,
+ );
+ log.warn(
+ 'initial view is not ready, falling back to global view',
+ );
+ await map.gotoView(0, 0, 2);
+ }
}
- await map.gotoView(view.center.lat, view.center.lon, view.zoomLevel);
+ } catch (err) {
+ log.warn('wallet page map sync failed', err);
}
}
}