From 1c8f71f60b2eda20df1bb854e20c86a5df680d63 Mon Sep 17 00:00:00 2001 From: tnagorra Date: Thu, 26 Dec 2024 15:44:55 +0545 Subject: [PATCH] Use GlobalMap in-place of BaseMap - Remove withoutLabel prop on BaseMap - Move label translation feature from GlobalMap to BaseMap - Add adminZeroFillPaint on BaseMap - Rename handlers - Fix issue with mapboxgl filter on re-map --- .../domain/ActiveOperationMap/index.tsx | 2 +- app/src/components/domain/BaseMap/index.tsx | 114 ++++++------------ app/src/components/domain/GlobalMap/index.tsx | 84 ++----------- .../domain/RiskImminentEventMap/index.tsx | 6 +- .../domain/RiskSeasonalMap/index.tsx | 109 +++++++---------- .../CountryNsOverviewActivities/Map/index.tsx | 22 ++-- .../LocalUnitsMap/index.tsx | 2 +- .../index.tsx | 45 ++----- .../PopulationMap/index.tsx | 1 - app/src/views/Emergencies/Map/index.tsx | 45 ++----- app/src/views/GlobalThreeW/Map/index.tsx | 26 ++-- .../MovementActivitiesMap/index.tsx | 22 ++-- patches/@togglecorp__re-map@0.3.0.patch | 15 ++- pnpm-lock.yaml | 6 +- 14 files changed, 158 insertions(+), 341 deletions(-) diff --git a/app/src/components/domain/ActiveOperationMap/index.tsx b/app/src/components/domain/ActiveOperationMap/index.tsx index f9713e9c98..088e8c9394 100644 --- a/app/src/components/domain/ActiveOperationMap/index.tsx +++ b/app/src/components/domain/ActiveOperationMap/index.tsx @@ -432,7 +432,7 @@ function ActiveOperationMap(props: Props) { )} > & { baseLayers?: React.ReactNode; withDisclaimer?: boolean; - // NOTE: Labels with be added from the country information instead of the - // mapbox layers - withoutLabel?: boolean; } & Partial>; -const sourceOptions: mapboxgl.GeoJSONSourceRaw = { - type: 'geojson', -}; - -const adminLabelOverrideOptions: Omit = { - type: 'symbol', - layout: { - 'text-field': ['get', 'name'], - 'text-font': ['Poppins Regular', 'Arial Unicode MS Regular'], - 'text-letter-spacing': 0.15, - 'text-line-height': 1.2, - 'text-max-width': 8, - 'text-justify': 'center', - 'text-anchor': 'top', - 'text-padding': 2, - 'text-size': [ - 'interpolate', ['linear', 1], ['zoom'], - 0, 6, - 6, 16, - ], - }, - paint: { - 'text-color': '#000000', - 'text-halo-color': '#555555', - 'text-halo-width': 0.2, - }, -}; - function BaseMap(props: Props) { const { baseLayers, @@ -71,36 +38,33 @@ function BaseMap(props: Props) { navControlOptions, scaleControlShown, children, - withoutLabel = false, ...otherProps } = props; - const countries = useCountry(); + const { currentLanguage } = useContext(LanguageContext); - // FIXME: We should check for special cases like ICRC, IFRC, etc. - const countryCentroidGeoJson = useMemo( - (): GeoJSON.FeatureCollection => ({ - type: 'FeatureCollection' as const, - features: countries - ?.map((country) => { - if (isFalsyString(country.name) || isNotDefined(country.centroid)) { - return undefined; - } + const adminLabelLayerOptions : Omit = useMemo( + () => { + // ar, es, fr + let label: string; + if (currentLanguage === 'es') { + label = 'name_es'; + } else if (currentLanguage === 'ar') { + label = 'name_ar'; + } else if (currentLanguage === 'fr') { + label = 'name_fr'; + } else { + label = 'name'; + } - return { - type: 'Feature' as const, - geometry: country.centroid as { - type: 'Point', - coordinates: [number, number], - }, - properties: { - id: country.id, - name: country.name, - }, - }; - }).filter(isDefined) ?? [], - }), - [countries], + return { + type: 'symbol', + layout: { + 'text-field': ['get', label], + }, + }; + }, + [currentLanguage], ); return ( @@ -118,20 +82,20 @@ function BaseMap(props: Props) { sourceKey="composite" managed={false} > + + + {baseLayers} - {!withoutLabel && ( - - - - )} {children} ); diff --git a/app/src/components/domain/GlobalMap/index.tsx b/app/src/components/domain/GlobalMap/index.tsx index 7df3025afb..8c0da45d11 100644 --- a/app/src/components/domain/GlobalMap/index.tsx +++ b/app/src/components/domain/GlobalMap/index.tsx @@ -1,18 +1,14 @@ import { - useContext, useMemo, useState, } from 'react'; -import { LanguageContext } from '@ifrc-go/ui/contexts'; import { MapLayer } from '@togglecorp/re-map'; import { type Expression, type FillLayer, type FillPaint, - type LineLayer, type LngLatLike, type MapboxGeoJSONFeature, - type SymbolLayer, } from 'mapbox-gl'; import BaseMap, { type Props as BaseMapProps } from '#components/domain/BaseMap'; @@ -62,19 +58,23 @@ const adminZeroHighlightPaint: FillPaint = { ], }; -interface Props extends Omit { - onHover?: (hoveredFeatureProperties: AdminZeroFeatureProperties | undefined) => void; - onClick?: ( +interface Props extends BaseMapProps { + adminZeroFillPaint?: mapboxgl.FillPaint, + onAdminZeroFillHover?: ( + hoveredFeatureProperties: AdminZeroFeatureProperties | undefined + ) => void; + onAdminZeroFillClick?: ( clickedFeatureProperties: AdminZeroFeatureProperties, lngLat: LngLatLike, ) => void; - activeCountryIso3?: string | undefined | null; } function GlobalMap(props: Props) { const { - onHover, - onClick, + onAdminZeroFillHover: onHover, + onAdminZeroFillClick: onClick, + adminZeroFillPaint, + baseLayers, ...baseMapProps } = props; @@ -146,52 +146,15 @@ function GlobalMap(props: Props) { visibility: 'visible', 'fill-sort-key': fillSortKey, }, + paint: adminZeroFillPaint, }), - [fillSortKey], - ); - - const adminZeroLineLayerOptions = useMemo>( - () => ({ - type: 'line', - layout: { - visibility: 'visible', - }, - }), - [], - ); - - const { currentLanguage } = useContext(LanguageContext); - - const adminLabelLayerOptions : Omit = useMemo( - () => { - // ar, es, fr - let label: string; - if (currentLanguage === 'es') { - label = 'name_es'; - } else if (currentLanguage === 'ar') { - label = 'name_ar'; - } else if (currentLanguage === 'fr') { - label = 'name_fr'; - } else { - label = 'name'; - } - - return { - type: 'symbol', - layout: { - 'text-field': ['get', label], - visibility: 'visible', - }, - }; - }, - [currentLanguage], + [fillSortKey, adminZeroFillPaint], ); return ( - - - - {/* - - */} - {(onHover || onClick) && ( )} + {baseLayers} )} /> diff --git a/app/src/components/domain/RiskImminentEventMap/index.tsx b/app/src/components/domain/RiskImminentEventMap/index.tsx index 9622417d65..88d0a532e5 100644 --- a/app/src/components/domain/RiskImminentEventMap/index.tsx +++ b/app/src/components/domain/RiskImminentEventMap/index.tsx @@ -29,7 +29,7 @@ import type { SymbolLayer, } from 'mapbox-gl'; -import BaseMap from '#components/domain/BaseMap'; +import GlobalMap from '#components/domain/GlobalMap'; import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer'; import { type components } from '#generated/riskTypes'; import useDebouncedValue from '#hooks/useDebouncedValue'; @@ -347,7 +347,7 @@ function RiskImminentEventMap< return (
- )} - + ; - lngLat: mapboxgl.LngLatLike; -} - -interface GeoJsonProps { - country_id: number; - disputed: boolean; - fdrs: string; - independent: boolean; - is_deprecated: boolean; - iso: string; - iso3: string; - name: string; - record_type: number; - region_id: number; + properties: AdminZeroFeatureProperties; + lngLat: LngLatLike; } type BaseProps = { @@ -813,55 +798,49 @@ function RiskSeasonalMap(props: Props) { // NOTE: we need to generate the layerOptions because we cannot use MapState // The id in the vector tile does not match the id in GO // We also cannot use promoteId as it is a non-managed mapbox source - const layerOptions = useMemo>( + const paintOptions = useMemo( () => { if (isNotDefined(filteredData) || filteredData.length === 0) { return { - type: 'fill', - paint: { - 'fill-color': COLOR_LIGHT_GREY, - }, + 'fill-color': COLOR_LIGHT_GREY, }; } return { - type: 'fill', - paint: { - 'fill-color': [ - 'match', - ['get', 'iso3'], - ...filteredData.flatMap( - (item) => [ - item.country_details.iso3.toUpperCase(), - [ - 'interpolate', - ['linear'], - ['number', item.riskCategory], - CATEGORY_RISK_VERY_LOW, - COLOR_LIGHT_BLUE, - CATEGORY_RISK_VERY_HIGH, - COLOR_PRIMARY_RED, - ], + 'fill-color': [ + 'match', + ['get', 'iso3'], + ...filteredData.flatMap( + (item) => [ + item.country_details.iso3.toUpperCase(), + [ + 'interpolate', + ['linear'], + ['number', item.riskCategory], + CATEGORY_RISK_VERY_LOW, + COLOR_LIGHT_BLUE, + CATEGORY_RISK_VERY_HIGH, + COLOR_PRIMARY_RED, ], - ), - COLOR_LIGHT_GREY, - ], - 'fill-outline-color': [ - 'case', - ['boolean', ['feature-state', 'hovered'], false], - COLOR_DARK_GREY, - 'transparent', - ], - }, + ], + ), + COLOR_LIGHT_GREY, + ], + 'fill-outline-color': [ + 'case', + ['boolean', ['feature-state', 'hovered'], false], + COLOR_DARK_GREY, + 'transparent', + ], }; }, [filteredData], ); const handleCountryClick = useCallback( - (feature: mapboxgl.MapboxGeoJSONFeature, lngLat: mapboxgl.LngLat) => { + (properties: AdminZeroFeatureProperties, lngLat: LngLatLike) => { setClickedPointProperties({ - feature: feature as unknown as ClickedPoint['feature'], + properties, lngLat, }); return true; @@ -879,7 +858,7 @@ function RiskSeasonalMap(props: Props) { const riskPopupValue = useMemo(() => ( filteredData?.find( (filter) => filter.iso3 === clickedPointProperties - ?.feature.properties.iso3.toLowerCase(), + ?.properties.iso3.toLowerCase(), ) ), [filteredData, clickedPointProperties]); @@ -952,15 +931,9 @@ function RiskSeasonalMap(props: Props) {
)} > - - )} + - {clickedPointProperties.feature.properties.name} + {clickedPointProperties.properties.name} )} contentViewType="vertical" @@ -994,7 +967,7 @@ function RiskSeasonalMap(props: Props) { /> )} - +
{ + (properties: AdminZeroFeatureProperties, lngLat: mapboxgl.LngLatLike) => { setClickedPointProperties({ - countryId: feature.properties?.country_id, - countryName: feature.properties?.name, + countryId: properties?.country_id, + countryName: properties?.name, lngLat, }); return true; @@ -337,15 +336,8 @@ function CountryThreeWNationalSocietyProjectsMap(props: Props) { return (
- - )} + )} - +
{sidebarContent && (
diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsMap/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsMap/index.tsx index 3cc1dfe02c..572cc4ccaa 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsMap/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitsMap/index.tsx @@ -368,8 +368,8 @@ function LocalUnitsMap(props: Props) { >
void; } -interface CountryProperties { - country_id: number; - disputed: boolean; - fdrs: string; - independent: boolean; - is_deprecated: boolean; - iso: string; - iso3: string; - name: string; - name_ar: string; - name_es: string; - name_fr: string; - record_type: number; - region_id: number; -} - interface ClickedPoint { - feature: GeoJSON.Feature; + properties: AdminZeroFeatureProperties; lngLat: mapboxgl.LngLatLike; } @@ -403,11 +386,11 @@ export function Component(props: BaseProps) { ]); const handleCountryClick = useCallback(( - feature: mapboxgl.MapboxGeoJSONFeature, + properties: AdminZeroFeatureProperties, lngLat: mapboxgl.LngLatLike, ) => { setClickedPointProperties({ - feature: feature as unknown as ClickedPoint['feature'], + properties, lngLat, }); return false; @@ -457,7 +440,7 @@ export function Component(props: BaseProps) { ]); const popupDetails = clickedPointProperties - ? countryGroupedAppeal[clickedPointProperties.feature.properties.iso3] + ? countryGroupedAppeal[clickedPointProperties.properties.iso3] : undefined; return ( @@ -535,15 +518,8 @@ export function Component(props: BaseProps) { )} contentViewType="vertical" > - - )} + - {clickedPointProperties.feature.properties.name} + {clickedPointProperties.properties.name} )} childrenContainerClassName={styles.popupContent} @@ -650,7 +625,7 @@ export function Component(props: BaseProps) { padding={DEFAULT_MAP_PADDING} /> )} - + {onPresentationModeButtonClick && !presentationMode && (