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); } } }