From da8efa88342a53548baf36374df2648989f701f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 10 Oct 2024 09:28:07 +0200 Subject: [PATCH 1/3] Rename `bboxLocation` as `bboxLocationAtom` --- frontend/src/containers/map/content/map/index.tsx | 6 +++--- frontend/src/containers/map/content/map/popup/eez/index.tsx | 4 ++-- .../src/containers/map/content/map/popup/regions/index.tsx | 4 ++-- frontend/src/containers/map/store.ts | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/containers/map/content/map/index.tsx b/frontend/src/containers/map/content/map/index.tsx index 9c0208af..98d24109 100644 --- a/frontend/src/containers/map/content/map/index.tsx +++ b/frontend/src/containers/map/content/map/index.tsx @@ -26,7 +26,7 @@ import RegionsPopup from '@/containers/map/content/map/popup/regions'; import { useSyncMapLayers, useSyncMapSettings } from '@/containers/map/content/map/sync-settings'; import { sidebarAtom } from '@/containers/map/store'; import { - bboxLocation, + bboxLocationAtom, drawStateAtom, layersInteractiveAtom, layersInteractiveIdsAtom, @@ -51,8 +51,8 @@ const MainMap: FCWithMessages = () => { const isSidebarOpen = useAtomValue(sidebarAtom); const [popup, setPopup] = useAtom(popupAtom); const params = useParams(); - const [locationBbox, setLocationBbox] = useAtom(bboxLocation); - const resetLocationBbox = useResetAtom(bboxLocation); + const [locationBbox, setLocationBbox] = useAtom(bboxLocationAtom); + const resetLocationBbox = useResetAtom(bboxLocationAtom); const hoveredPolygonId = useRef[0] | null>(null); const [cursor, setCursor] = useState<'grab' | 'crosshair' | 'pointer'>('grab'); diff --git a/frontend/src/containers/map/content/map/popup/eez/index.tsx b/frontend/src/containers/map/content/map/popup/eez/index.tsx index c244705a..c3bd8a0c 100644 --- a/frontend/src/containers/map/content/map/popup/eez/index.tsx +++ b/frontend/src/containers/map/content/map/popup/eez/index.tsx @@ -12,7 +12,7 @@ import { useLocale, useTranslations } from 'next-intl'; import { CustomMapProps } from '@/components/map/types'; import { PAGES } from '@/constants/pages'; import { useMapSearchParams } from '@/containers/map/content/map/sync-settings'; -import { bboxLocation, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; +import { bboxLocationAtom, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; import { FCWithMessages } from '@/types'; import { useGetLayersId } from '@/types/generated/layer'; @@ -29,7 +29,7 @@ const EEZLayerPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const { default: map } = useMap(); const searchParams = useMapSearchParams(); const { push } = useRouter(); - const [, setLocationBBox] = useAtom(bboxLocation); + const [, setLocationBBox] = useAtom(bboxLocationAtom); const [popup, setPopup] = useAtom(popupAtom); const { locationCode } = useParams(); diff --git a/frontend/src/containers/map/content/map/popup/regions/index.tsx b/frontend/src/containers/map/content/map/popup/regions/index.tsx index 0d591eab..2ce27547 100644 --- a/frontend/src/containers/map/content/map/popup/regions/index.tsx +++ b/frontend/src/containers/map/content/map/popup/regions/index.tsx @@ -11,7 +11,7 @@ import { useLocale, useTranslations } from 'next-intl'; import { CustomMapProps } from '@/components/map/types'; import { PAGES } from '@/constants/pages'; import { useMapSearchParams } from '@/containers/map/content/map/sync-settings'; -import { bboxLocation, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; +import { bboxLocationAtom, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; import { FCWithMessages } from '@/types'; import { useGetLayersId } from '@/types/generated/layer'; @@ -28,7 +28,7 @@ const RegionsPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const { default: map } = useMap(); const searchParams = useMapSearchParams(); const { push } = useRouter(); - const setLocationBBox = useSetAtom(bboxLocation); + const setLocationBBox = useSetAtom(bboxLocationAtom); const [popup, setPopup] = useAtom(popupAtom); const layersInteractiveIds = useAtomValue(layersInteractiveIdsAtom); diff --git a/frontend/src/containers/map/store.ts b/frontend/src/containers/map/store.ts index 32dfc20f..87ed12c4 100644 --- a/frontend/src/containers/map/store.ts +++ b/frontend/src/containers/map/store.ts @@ -14,7 +14,7 @@ export const layersAtom = atom(true); // ? Map state export const layersInteractiveAtom = atom([]); export const layersInteractiveIdsAtom = atom([]); -export const bboxLocation = atomWithReset([ +export const bboxLocationAtom = atomWithReset([ -180, -85.5624999997749, 180, 90, ]); export const popupAtom = atom>({}); From cba2d8d8ba849f3d2d95298a1f1b64b01c9a6ea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 10 Oct 2024 09:32:24 +0200 Subject: [PATCH 2/3] Do not change bounds when clicking in popup --- .../containers/map/content/map/popup/eez/index.tsx | 11 ++++------- .../map/content/map/popup/regions/index.tsx | 13 +++++-------- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/frontend/src/containers/map/content/map/popup/eez/index.tsx b/frontend/src/containers/map/content/map/popup/eez/index.tsx index c3bd8a0c..089bb5ca 100644 --- a/frontend/src/containers/map/content/map/popup/eez/index.tsx +++ b/frontend/src/containers/map/content/map/popup/eez/index.tsx @@ -9,10 +9,9 @@ import type { Feature } from 'geojson'; import { useAtom, useAtomValue } from 'jotai'; import { useLocale, useTranslations } from 'next-intl'; -import { CustomMapProps } from '@/components/map/types'; import { PAGES } from '@/constants/pages'; import { useMapSearchParams } from '@/containers/map/content/map/sync-settings'; -import { bboxLocationAtom, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; +import { layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; import { FCWithMessages } from '@/types'; import { useGetLayersId } from '@/types/generated/layer'; @@ -29,7 +28,6 @@ const EEZLayerPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const { default: map } = useMap(); const searchParams = useMapSearchParams(); const { push } = useRouter(); - const [, setLocationBBox] = useAtom(bboxLocationAtom); const [popup, setPopup] = useAtom(popupAtom); const { locationCode } = useParams(); @@ -109,7 +107,7 @@ const EEZLayerPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { // @ts-ignore populate: { location: { - fields: ['code', 'marine_bounds', 'total_marine_area'], + fields: ['code', 'total_marine_area'], }, }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -164,12 +162,11 @@ const EEZLayerPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const handleLocationSelected = useCallback(async () => { if (!protectionCoverageStats?.location?.data.attributes) return undefined; - const { code, marine_bounds: bounds } = protectionCoverageStats.location.data.attributes; + const { code } = protectionCoverageStats.location.data.attributes; await push(`${PAGES.progressTracker}/${code.toUpperCase()}?${searchParams.toString()}`); - setLocationBBox(bounds as CustomMapProps['bounds']['bbox']); setPopup({}); - }, [push, searchParams, setLocationBBox, protectionCoverageStats, setPopup]); + }, [push, searchParams, protectionCoverageStats, setPopup]); useEffect(() => { map?.on('render', handleMapRender); diff --git a/frontend/src/containers/map/content/map/popup/regions/index.tsx b/frontend/src/containers/map/content/map/popup/regions/index.tsx index 2ce27547..6dbb6441 100644 --- a/frontend/src/containers/map/content/map/popup/regions/index.tsx +++ b/frontend/src/containers/map/content/map/popup/regions/index.tsx @@ -5,13 +5,12 @@ import { useMap } from 'react-map-gl'; import { useRouter } from 'next/router'; import type { Feature } from 'geojson'; -import { useAtom, useAtomValue, useSetAtom } from 'jotai'; +import { useAtom, useAtomValue } from 'jotai'; import { useLocale, useTranslations } from 'next-intl'; -import { CustomMapProps } from '@/components/map/types'; import { PAGES } from '@/constants/pages'; import { useMapSearchParams } from '@/containers/map/content/map/sync-settings'; -import { bboxLocationAtom, layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; +import { layersInteractiveIdsAtom, popupAtom } from '@/containers/map/store'; import { formatPercentage, formatKM } from '@/lib/utils/formats'; import { FCWithMessages } from '@/types'; import { useGetLayersId } from '@/types/generated/layer'; @@ -28,7 +27,6 @@ const RegionsPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const { default: map } = useMap(); const searchParams = useMapSearchParams(); const { push } = useRouter(); - const setLocationBBox = useSetAtom(bboxLocationAtom); const [popup, setPopup] = useAtom(popupAtom); const layersInteractiveIds = useAtomValue(layersInteractiveIdsAtom); @@ -112,7 +110,7 @@ const RegionsPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { // @ts-ignore populate: { location: { - fields: ['name', 'name_es', 'name_fr', 'code', 'marine_bounds', 'total_marine_area'], + fields: ['name', 'name_es', 'name_fr', 'code', 'total_marine_area'], }, }, // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -172,12 +170,11 @@ const RegionsPopup: FCWithMessages<{ layerId: number }> = ({ layerId }) => { const handleLocationSelected = useCallback(async () => { if (!protectionCoverageStats?.location?.data.attributes) return undefined; - const { code, marine_bounds: bounds } = protectionCoverageStats.location.data.attributes; + const { code } = protectionCoverageStats.location.data.attributes; await push(`${PAGES.progressTracker}/${code.toUpperCase()}?${searchParams.toString()}`); - setLocationBBox(bounds as CustomMapProps['bounds']['bbox']); setPopup({}); - }, [push, searchParams, setLocationBBox, protectionCoverageStats, setPopup]); + }, [push, searchParams, protectionCoverageStats, setPopup]); useEffect(() => { map?.on('render', handleMapRender); From 198c513e88ae451f6a868c40f054ab089fcdd223 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Prod=27homme?= Date: Thu, 10 Oct 2024 10:11:14 +0200 Subject: [PATCH 3/3] Change the bounds when changing tab --- .../main-panel/panels/details/index.tsx | 44 ++++++++++++++++++- frontend/src/lib/utils/geo.ts | 16 +++++++ 2 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 frontend/src/lib/utils/geo.ts diff --git a/frontend/src/containers/map/sidebar/main-panel/panels/details/index.tsx b/frontend/src/containers/map/sidebar/main-panel/panels/details/index.tsx index 5ac50b14..c9fcb2f2 100644 --- a/frontend/src/containers/map/sidebar/main-panel/panels/details/index.tsx +++ b/frontend/src/containers/map/sidebar/main-panel/panels/details/index.tsx @@ -2,16 +2,22 @@ import { useCallback, useEffect, useMemo, useRef } from 'react'; import { useRouter } from 'next/router'; +import { BBox } from '@turf/turf'; +import { useAtom } from 'jotai'; import { useLocale, useTranslations } from 'next-intl'; +import { CustomMapProps } from '@/components/map/types'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { PAGES } from '@/constants/pages'; import { useMapSearchParams } from '@/containers/map/content/map/sync-settings'; +import { bboxLocationAtom } from '@/containers/map/store'; import { useSyncMapContentSettings } from '@/containers/map/sync-settings'; import useScrollPosition from '@/hooks/use-scroll-position'; import { cn } from '@/lib/classnames'; +import { combineBoundingBoxes } from '@/lib/utils/geo'; import { FCWithMessages } from '@/types'; import { useGetLocations } from '@/types/generated/location'; +import { Location } from '@/types/generated/strapi.schemas'; import LocationSelector from '../../location-selector'; @@ -35,13 +41,23 @@ const SidebarDetails: FCWithMessages = () => { const searchParams = useMapSearchParams(); const [{ tab }, setSettings] = useSyncMapContentSettings(); + const [, setLocationBBox] = useAtom(bboxLocationAtom); const { data: locationsData } = useGetLocations({ locale, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + fields: ['name', 'name_es', 'name_fr', 'marine_bounds', 'terrestrial_bounds'], filters: { code: locationCode, }, - populate: 'members', + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + populate: { + members: { + fields: ['code', 'name', 'name_es', 'name_fr'], + }, + }, }); const locationNameField = useMemo(() => { @@ -55,6 +71,25 @@ const SidebarDetails: FCWithMessages = () => { return res; }, [locale]); + const locationBounds = useMemo(() => { + const { terrestrial_bounds, marine_bounds } = + locationsData?.data[0]?.attributes ?? ({} as Location); + + if (tab === 'terrestrial') { + return terrestrial_bounds; + } + + if (tab === 'marine') { + return marine_bounds; + } + + if (terrestrial_bounds === undefined || marine_bounds === undefined) { + return null; + } + + return combineBoundingBoxes(terrestrial_bounds as BBox, marine_bounds as BBox); + }, [locationsData, tab]); + const memberCountries = useMemo(() => { return locationsData?.data[0]?.attributes?.members?.data?.map(({ attributes }) => ({ code: attributes?.code, @@ -80,6 +115,13 @@ const SidebarDetails: FCWithMessages = () => { containerRef.current?.scrollTo({ top: 0 }); }, [tab, locationCode]); + // Zoom the map to the location's bounds (terrestrial bounds, marine bounds or both) + useEffect(() => { + if (locationBounds) { + setLocationBBox(locationBounds as CustomMapProps['bounds']['bbox']); + } + }, [setLocationBBox, locationBounds]); + return (
{ + return [ + Math.min(bbox1[0], bbox2[0]), + Math.min(bbox1[1], bbox2[1]), + Math.max(bbox1[2], bbox2[2]), + Math.max(bbox1[3], bbox2[3]), + ]; +};