diff --git a/app/layout/projects/show/map/legend/hooks/index.ts b/app/layout/projects/show/map/legend/hooks/index.ts index 6a7857cdb2..717a786ffd 100644 --- a/app/layout/projects/show/map/legend/hooks/index.ts +++ b/app/layout/projects/show/map/legend/hooks/index.ts @@ -110,71 +110,6 @@ export const useConservationAreasLegend = () => { }); }; -export const useFeatureAbundanceLegend = () => { - const { query } = useRouter(); - const { pid } = query as { pid: string }; - - const dispatch = useAppDispatch(); - const projectFeaturesQuery = useAllFeatures( - pid, - { sort: 'feature_class_name' }, - { - select: ({ data }) => data, - } - ); - - const { layerSettings, selectedFeatures: visibleFeatures } = useAppSelector( - (state) => state['/projects/[id]'] - ); - - const totalItems = projectFeaturesQuery.data?.length || 0; - - const items = - projectFeaturesQuery.data?.map( - ({ id, featureClassName, amountRange = { min: 5000, max: 100000 } }, index) => { - const color = - totalItems > COLORS['features-preview'].ramp.length - ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] - : COLORS['features-preview'].ramp[index]; - - return { - id, - name: featureClassName, - amountRange, - color, - }; - } - ) || []; - - return LEGEND_LAYERS['features-abundance']({ - items, - onChangeVisibility: (featureId: Feature['id']) => { - const { color, amountRange } = items.find(({ id }) => id === featureId) || {}; - - const newSelectedFeatures = [...visibleFeatures]; - const isIncluded = newSelectedFeatures.includes(featureId); - if (!isIncluded) { - newSelectedFeatures.push(featureId); - } else { - const i = newSelectedFeatures.indexOf(featureId); - newSelectedFeatures.splice(i, 1); - } - dispatch(setSelectedFeatures(newSelectedFeatures)); - - dispatch( - setLayerSettings({ - id: featureId, - settings: { - visibility: !layerSettings[featureId]?.visibility, - amountRange, - color, - }, - }) - ); - }, - }); -}; - export const useFeaturesLegend = () => { const { selectedFeatures } = useAppSelector((state) => state['/projects/[id]']); const { query } = useRouter(); @@ -185,14 +120,25 @@ export const useFeaturesLegend = () => { pid, { sort: 'feature_class_name' }, { - select: ({ data }) => data, + select: ({ data }) => ({ + binaryFeatures: + data?.filter( + (feature) => !Object.hasOwn(feature, 'min') && !Object.hasOwn(feature, 'max') + ) || [], + continuousFeatures: + data?.filter( + (feature) => Object.hasOwn(feature, 'min') && Object.hasOwn(feature, 'max') + ) || [], + }), } ); - const totalItems = projectFeaturesQuery.data?.length || 0; + const totalItems = + projectFeaturesQuery.data?.binaryFeatures.length + + projectFeaturesQuery.data?.continuousFeatures.length || 0; - const items = - projectFeaturesQuery.data?.map(({ id, featureClassName }, index) => { + const binaryFeaturesItems = + projectFeaturesQuery.data?.binaryFeatures?.map(({ id, featureClassName }, index) => { const color = totalItems > COLORS['features-preview'].ramp.length ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] @@ -205,32 +151,79 @@ export const useFeaturesLegend = () => { }; }) || []; - return LEGEND_LAYERS['features-preview-new']({ - items, - onChangeVisibility: (featureId: Feature['id']) => { - const newSelectedFeatures = [...selectedFeatures]; - const isIncluded = newSelectedFeatures.includes(featureId); - if (!isIncluded) { - newSelectedFeatures.push(featureId); - } else { - const i = newSelectedFeatures.indexOf(featureId); - newSelectedFeatures.splice(i, 1); - } - dispatch(setSelectedFeatures(newSelectedFeatures)); + const continuousFeaturesItems = + projectFeaturesQuery.data?.continuousFeatures.map( + ({ id, featureClassName, amountRange = { min: 5000, max: 100000 } }, index) => { + const color = + totalItems > COLORS['features-preview'].ramp.length + ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] + : COLORS['features-preview'].ramp[index]; - const { color } = items.find(({ id }) => id === featureId) || {}; + return { + id, + name: featureClassName, + amountRange, + color, + }; + } + ) || []; - dispatch( - setLayerSettings({ - id: featureId, - settings: { - visibility: !isIncluded, - color, - }, - }) - ); - }, - }); + return [ + ...LEGEND_LAYERS['features-preview-new']({ + items: binaryFeaturesItems, + onChangeVisibility: (featureId: Feature['id']) => { + const newSelectedFeatures = [...selectedFeatures]; + const isIncluded = newSelectedFeatures.includes(featureId); + if (!isIncluded) { + newSelectedFeatures.push(featureId); + } else { + const i = newSelectedFeatures.indexOf(featureId); + newSelectedFeatures.splice(i, 1); + } + dispatch(setSelectedFeatures(newSelectedFeatures)); + + const { color } = binaryFeaturesItems.find(({ id }) => id === featureId) || {}; + + dispatch( + setLayerSettings({ + id: featureId, + settings: { + visibility: !isIncluded, + color, + }, + }) + ); + }, + }), + ...LEGEND_LAYERS['features-abundance']({ + items: continuousFeaturesItems, + onChangeVisibility: (featureId: Feature['id']) => { + const { color, amountRange } = + continuousFeaturesItems.find(({ id }) => id === featureId) || {}; + + const newSelectedFeatures = [...selectedFeatures]; + const isIncluded = newSelectedFeatures.includes(featureId); + if (!isIncluded) { + newSelectedFeatures.push(featureId); + } else { + const i = newSelectedFeatures.indexOf(featureId); + newSelectedFeatures.splice(i, 1); + } + dispatch(setSelectedFeatures(newSelectedFeatures)); + + dispatch( + setLayerSettings({ + id: featureId, + settings: { + visibility: !isIncluded, + amountRange, + color, + }, + }) + ); + }, + }), + ]; }; export const useComparisonScenariosLegend = ({ @@ -300,11 +293,7 @@ export const useInventoryLegend = ({ layers: useConservationAreasLegend(), }, { - name: 'Features (Continuous)', - layers: useFeatureAbundanceLegend(), - }, - { - name: 'Features (Binary)', + name: 'Features', layers: useFeaturesLegend(), }, ]; diff --git a/app/layout/scenarios/edit/map/legend/hooks/index.ts b/app/layout/scenarios/edit/map/legend/hooks/index.ts index 92021ca8ee..4865272de7 100644 --- a/app/layout/scenarios/edit/map/legend/hooks/index.ts +++ b/app/layout/scenarios/edit/map/legend/hooks/index.ts @@ -7,7 +7,7 @@ import chroma from 'chroma-js'; import { orderBy, sortBy } from 'lodash'; import { useProjectCostSurfaces } from 'hooks/cost-surface'; -import { useSelectedFeatures } from 'hooks/features'; +import { useAllFeatures } from 'hooks/features'; import { useAllGapAnalysis } from 'hooks/gap-analysis'; import { COLORS, LEGEND_LAYERS } from 'hooks/map/constants'; import { useProject } from 'hooks/projects'; @@ -119,69 +119,39 @@ export const useConservationAreasLegend = () => { }); }; -export const useFeatureAbundanceLegend = () => { - const { query } = useRouter(); - const { sid } = query as { sid: string }; - - const dispatch = useAppDispatch(); - const { data: features } = useSelectedFeatures(sid); - const scenarioSlice = getScenarioEditSlice(sid); - const { setLayerSettings } = scenarioSlice.actions; - - const { layerSettings } = useAppSelector((state) => state[`/scenarios/${sid}/edit`]); - - const totalItems = features?.length || 0; - - const items = - features?.map(({ id, name, amountRange = { min: 5000, max: 100000 } }, index) => { - const color = - totalItems > COLORS['features-preview'].ramp.length - ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] - : COLORS['features-preview'].ramp[index]; - - return { - id, - name, - amountRange, - color, - }; - }) || []; - - return LEGEND_LAYERS['features-abundance']({ - items, - onChangeVisibility: (featureId: Feature['id']) => { - const { color, amountRange } = items.find(({ id }) => id === featureId) || {}; - - dispatch( - setLayerSettings({ - id: featureId, - settings: { - visibility: !layerSettings[featureId]?.visibility, - amountRange, - color, - }, - }) - ); - }, - }); -}; - export const useFeaturesLegend = () => { const { query } = useRouter(); - const { sid } = query as { sid: string }; - - const dispatch = useAppDispatch(); - const { data: features } = useSelectedFeatures(sid); + const { pid, sid } = query as { pid: string; sid: string }; const scenarioSlice = getScenarioEditSlice(sid); const { setSelectedFeatures, setLayerSettings } = scenarioSlice.actions; const { selectedFeatures }: { selectedFeatures: Feature['id'][] } = useAppSelector( (state) => state[`/scenarios/${sid}/edit`] ); - const totalItems = features?.length || 0; + const dispatch = useAppDispatch(); + const projectFeaturesQuery = useAllFeatures( + pid, + { sort: 'feature_class_name' }, + { + select: ({ data }) => ({ + binaryFeatures: + data?.filter( + (feature) => !Object.hasOwn(feature, 'min') && !Object.hasOwn(feature, 'max') + ) || [], + continuousFeatures: + data?.filter( + (feature) => Object.hasOwn(feature, 'min') && Object.hasOwn(feature, 'max') + ) || [], + }), + } + ); - const items = - features?.map(({ id, name }, index) => { + const totalItems = + projectFeaturesQuery.data?.binaryFeatures.length + + projectFeaturesQuery.data?.continuousFeatures.length || 0; + + const binaryFeaturesItems = + projectFeaturesQuery.data?.binaryFeatures?.map(({ id, featureClassName }, index) => { const color = totalItems > COLORS['features-preview'].ramp.length ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] @@ -189,37 +159,84 @@ export const useFeaturesLegend = () => { return { id, - name, + name: featureClassName, color, }; }) || []; - return LEGEND_LAYERS['features-preview-new']({ - items, - onChangeVisibility: (featureId: Feature['id']) => { - const newSelectedFeatures = [...selectedFeatures]; - const isIncluded = newSelectedFeatures.includes(featureId); - if (!isIncluded) { - newSelectedFeatures.push(featureId); - } else { - const i = newSelectedFeatures.indexOf(featureId); - newSelectedFeatures.splice(i, 1); - } - dispatch(setSelectedFeatures(newSelectedFeatures)); + const continuousFeaturesItems = + projectFeaturesQuery.data?.continuousFeatures.map( + ({ id, featureClassName, amountRange = { min: 5000, max: 100000 } }, index) => { + const color = + totalItems > COLORS['features-preview'].ramp.length + ? chroma.scale(COLORS['features-preview'].ramp).colors(totalItems)[index] + : COLORS['features-preview'].ramp[index]; - const { color } = items.find(({ id }) => id === featureId) || {}; + return { + id, + name: featureClassName, + amountRange, + color, + }; + } + ) || []; - dispatch( - setLayerSettings({ - id: featureId, - settings: { - visibility: !isIncluded, - color, - }, - }) - ); - }, - }); + return [ + ...LEGEND_LAYERS['features-preview-new']({ + items: binaryFeaturesItems, + onChangeVisibility: (featureId: Feature['id']) => { + const newSelectedFeatures = [...selectedFeatures]; + const isIncluded = newSelectedFeatures.includes(featureId); + if (!isIncluded) { + newSelectedFeatures.push(featureId); + } else { + const i = newSelectedFeatures.indexOf(featureId); + newSelectedFeatures.splice(i, 1); + } + dispatch(setSelectedFeatures(newSelectedFeatures)); + + const { color } = binaryFeaturesItems.find(({ id }) => id === featureId) || {}; + + dispatch( + setLayerSettings({ + id: featureId, + settings: { + visibility: !isIncluded, + color, + }, + }) + ); + }, + }), + ...LEGEND_LAYERS['features-abundance']({ + items: continuousFeaturesItems, + onChangeVisibility: (featureId: Feature['id']) => { + const { color, amountRange } = + continuousFeaturesItems.find(({ id }) => id === featureId) || {}; + + const newSelectedFeatures = [...selectedFeatures]; + const isIncluded = newSelectedFeatures.includes(featureId); + if (!isIncluded) { + newSelectedFeatures.push(featureId); + } else { + const i = newSelectedFeatures.indexOf(featureId); + newSelectedFeatures.splice(i, 1); + } + dispatch(setSelectedFeatures(newSelectedFeatures)); + + dispatch( + setLayerSettings({ + id: featureId, + settings: { + visibility: !isIncluded, + amountRange, + color, + }, + }) + ); + }, + }), + ]; }; export const useLockInLegend = () => { @@ -463,11 +480,7 @@ export const useScenarioLegend = () => { layers: useConservationAreasLegend(), }, { - name: 'Features (Continuous)', - layers: useFeatureAbundanceLegend(), - }, - { - name: 'Features (Binary)', + name: 'Features', layers: useFeaturesLegend(), }, ];