diff --git a/packages/geoview-core/public/configs/navigator/28-geocore.json b/packages/geoview-core/public/configs/navigator/28-geocore.json
index 139ba497d62..d0dfec36113 100644
--- a/packages/geoview-core/public/configs/navigator/28-geocore.json
+++ b/packages/geoview-core/public/configs/navigator/28-geocore.json
@@ -17,18 +17,6 @@
{
"geoviewLayerType": "geoCore",
"geoviewLayerId": "ccc75c12-5acc-4a6a-959f-ef6f621147b9"
- },
- {
- "geoviewLayerType": "geoCore",
- "geoviewLayerId": "0fca08b5-e9d0-414b-a3c4-092ff9c5e326"
- },
- {
- "geoviewLayerType": "geoCore",
- "geoviewLayerId": "03ccfb5c-a06e-43e3-80fd-09d4f8f69703"
- },
- {
- "geoviewLayerType": "geoCore",
- "geoviewLayerId": "6433173f-bca8-44e6-be8e-3e8a19d3c299"
}
]
},
diff --git a/packages/geoview-core/src/core/components/legend/legend-layer-container.tsx b/packages/geoview-core/src/core/components/legend/legend-layer-container.tsx
new file mode 100644
index 00000000000..980d204d369
--- /dev/null
+++ b/packages/geoview-core/src/core/components/legend/legend-layer-container.tsx
@@ -0,0 +1,70 @@
+import { useTheme } from '@mui/material';
+import { memo } from 'react';
+import { Box, Collapse, List } from '@/ui';
+import { TypeLegendLayer } from '@/core/components/layers/types';
+import { getSxClasses } from './legend-styles';
+import { logger } from '@/core/utils/logger';
+import { CV_CONST_LAYER_TYPES } from '@/api/config/types/config-constants';
+import { ItemsList } from './legend-layer-items';
+
+// Define component types and interfaces
+type LegendLayerType = React.FC<{ layer: TypeLegendLayer }>;
+
+interface CollapsibleContentProps {
+ layer: TypeLegendLayer;
+ legendExpanded: boolean;
+ initLightBox: (imgSrc: string, title: string, index: number, total: number) => void;
+ childLayers: TypeLegendLayer[];
+ items: TypeLegendLayer['items'];
+ LegendLayerComponent: LegendLayerType;
+}
+
+// CollapsibleContent component moved after LegendLayer
+export const CollapsibleContent = memo(function CollapsibleContent({
+ layer,
+ legendExpanded,
+ initLightBox,
+ childLayers,
+ items,
+ LegendLayerComponent,
+}: CollapsibleContentProps) {
+ logger.logDebug('legend1 collapsible', layer, childLayers, items);
+ const theme = useTheme();
+ const sxClasses = getSxClasses(theme);
+
+ if (layer.type === CV_CONST_LAYER_TYPES.WMS && layer.icons.length && layer.icons[0].iconImage && layer.icons[0].iconImage !== 'no data') {
+ const imgSrc = layer.icons[0].iconImage;
+ return (
+
+ initLightBox(imgSrc, '', 0, 2)}
+ onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter' ? initLightBox(imgSrc, '', 0, 2) : null)}
+ />
+
+ );
+ }
+
+ // if (!(childLayers?.length > 1 || items?.length > 1)) {
+ // return null;
+ // }
+
+ // TODO: childslayers always empty... seems to be use for items
+ return (
+
+ {layer.children?.length > 0 && (
+
+ {layer.children
+ .filter((d) => !['error', 'processing'].includes(d.layerStatus ?? ''))
+ .map((item) => (
+
+ ))}
+
+ )}
+
+
+ );
+});
diff --git a/packages/geoview-core/src/core/components/legend/legend-layer-ctrl.tsx b/packages/geoview-core/src/core/components/legend/legend-layer-ctrl.tsx
new file mode 100644
index 00000000000..bd993ee435c
--- /dev/null
+++ b/packages/geoview-core/src/core/components/legend/legend-layer-ctrl.tsx
@@ -0,0 +1,111 @@
+import { useTheme } from '@mui/material';
+import { memo, useCallback, useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import {
+ Box,
+ IconButton,
+ Stack,
+ VisibilityOutlinedIcon,
+ HighlightOutlinedIcon,
+ ZoomInSearchIcon,
+ Typography,
+ VisibilityOffOutlinedIcon,
+ HighlightIcon,
+} from '@/ui';
+import { useLayerHighlightedLayer, useLayerStoreActions } from '@/core/stores/store-interface-and-intial-values/layer-state';
+import { TypeLegendLayer } from '@/core/components/layers/types';
+import { useMapStoreActions } from '@/core/stores/';
+import { getSxClasses } from './legend-styles';
+import { logger } from '@/core/utils/logger';
+
+interface SecondaryControlsProps {
+ layer: TypeLegendLayer;
+ layerStatus: string;
+ itemsLength: number;
+ childLayers: TypeLegendLayer[];
+}
+
+// SecondaryControls component
+export const SecondaryControls = memo(function SecondaryControls({ layer, layerStatus, itemsLength, childLayers }: SecondaryControlsProps) {
+ logger.logDebug('legend1 - ctrl', layer, layerStatus, itemsLength, childLayers);
+ // Hooks
+ const { t } = useTranslation();
+ const theme = useTheme();
+ const sxClasses = getSxClasses(theme);
+
+ // Stores
+ const highlightedLayer = useLayerHighlightedLayer();
+ const { getVisibilityFromOrderedLayerInfo, setOrToggleLayerVisibility } = useMapStoreActions();
+ const { setHighlightLayer, zoomToLayerExtent } = useLayerStoreActions();
+
+ const [visibility, setVisibility] = useState(getVisibilityFromOrderedLayerInfo(layer.layerPath));
+ const isLayerVisible = layer.controls?.visibility ?? false;
+
+ // #region Handlers
+ const handleToggleVisibility = useCallback(
+ (e: React.MouseEvent): void => {
+ e.stopPropagation();
+ setOrToggleLayerVisibility(layer.layerPath);
+ setVisibility(getVisibilityFromOrderedLayerInfo(layer.layerPath));
+ },
+ [layer.layerPath, setOrToggleLayerVisibility]
+ );
+
+ const handleHighlightLayer = useCallback(
+ (e: React.MouseEvent): void => {
+ e.stopPropagation();
+ setHighlightLayer(layer.layerPath);
+ },
+ [layer.layerPath, setHighlightLayer]
+ );
+
+ const handleZoomTo = useCallback(
+ (e: React.MouseEvent): void => {
+ e.stopPropagation();
+ zoomToLayerExtent(layer.layerPath).catch((error) => {
+ logger.logPromiseFailed('in zoomToLayerExtent in legend-layer.handleZoomTo', error);
+ });
+ },
+ [layer.layerPath, zoomToLayerExtent]
+ );
+ // #endregion Handlers
+
+ if (!['processed', 'loaded'].includes(layerStatus)) {
+ return ;
+ }
+
+ let subTitle = '';
+ if (childLayers.length) {
+ subTitle = t('legend.subLayersCount').replace('{count}', childLayers.length.toString());
+ } else if (itemsLength > 1) {
+ subTitle = t('legend.itemsCount').replace('{count}', itemsLength.toString()).replace('{totalCount}', itemsLength.toString());
+ }
+
+ return (
+
+ {!!subTitle.length && {subTitle}}
+
+
+ {visibility ? : }
+
+
+ {highlightedLayer === layer.layerPath ? : }
+
+
+
+
+
+
+ );
+});
diff --git a/packages/geoview-core/src/core/components/legend/legend-layer-items.tsx b/packages/geoview-core/src/core/components/legend/legend-layer-items.tsx
new file mode 100644
index 00000000000..8b3ee083497
--- /dev/null
+++ b/packages/geoview-core/src/core/components/legend/legend-layer-items.tsx
@@ -0,0 +1,36 @@
+import { useTheme } from '@mui/material';
+import { memo } from 'react';
+import { Box, ListItem, Tooltip, ListItemText, ListItemIcon, List, BrowserNotSupportedIcon } from '@/ui';
+import { TypeLegendLayer } from '@/core/components/layers/types';
+import { getSxClasses } from './legend-styles';
+import { logger } from '@/core/utils/logger';
+
+interface ItemsListProps {
+ items: TypeLegendLayer['items'];
+}
+
+// ItemsList component
+export const ItemsList = memo(function ItemsList({ items }: ItemsListProps) {
+ logger.logDebug('legend1 item list', items);
+
+ // Hooks
+ const theme = useTheme();
+ const sxClasses = getSxClasses(theme);
+
+ if (!items?.length) {
+ return null;
+ }
+
+ return (
+
+ {items.map((item, index) => (
+
+ {item.icon ? : }
+
+
+
+
+ ))}
+
+ );
+});
diff --git a/packages/geoview-core/src/core/components/legend/legend-layer.tsx b/packages/geoview-core/src/core/components/legend/legend-layer.tsx
index 70d07b043e7..d01e3adbb21 100644
--- a/packages/geoview-core/src/core/components/legend/legend-layer.tsx
+++ b/packages/geoview-core/src/core/components/legend/legend-layer.tsx
@@ -1,215 +1,52 @@
-import { useTheme } from '@mui/material';
-import { useTranslation } from 'react-i18next';
-import {
- Box,
- ListItem,
- Tooltip,
- ListItemText,
- ListItemIcon,
- Collapse,
- List,
- BrowserNotSupportedIcon,
- IconButton,
- KeyboardArrowDownIcon,
- KeyboardArrowUpIcon,
- Stack,
- VisibilityOutlinedIcon,
- HighlightOutlinedIcon,
- ZoomInSearchIcon,
- Typography,
- VisibilityOffOutlinedIcon,
- HighlightIcon,
-} from '@/ui';
-import { useLayerHighlightedLayer, useLayerStoreActions } from '@/core/stores/store-interface-and-intial-values/layer-state';
+import { memo, useCallback, useMemo, useState } from 'react';
+import { ListItem, Tooltip, ListItemText, IconButton, KeyboardArrowDownIcon, KeyboardArrowUpIcon } from '@/ui';
import { TypeLegendLayer } from '@/core/components/layers/types';
import { useMapStoreActions } from '@/core/stores/';
-import { getSxClasses } from './legend-styles';
-import { LayerIcon } from '@/core/components/common/layer-icon';
import { logger } from '@/core/utils/logger';
-import { CV_CONST_LAYER_TYPES } from '@/api/config/types/config-constants';
import { useLightBox } from '@/core/components/common';
+import { LayerIcon } from '../common/layer-icon';
+import { SecondaryControls } from './legend-layer-ctrl';
+import { CollapsibleContent } from './legend-layer-container';
+
+// Define component types and interfaces
+type LegendLayerType = React.FC<{ layer: TypeLegendLayer }>;
interface LegendLayerProps {
layer: TypeLegendLayer;
}
-export function LegendLayer({ layer }: LegendLayerProps): JSX.Element {
- // Log
- logger.logTraceRender('components/legend/legend-layer');
+// Main LegendLayer component
+export const LegendLayer: LegendLayerType = memo(function LegendLayer({ layer }: LegendLayerProps) {
+ // Hooks
+ logger.logDebug('legend1 LegendLayerType', layer);
- const { t } = useTranslation();
- const theme = useTheme();
- const sxClasses = getSxClasses(theme);
+ // const { t } = useTranslation();
+ // const theme = useTheme();
+ // const sxClasses = getSxClasses(theme);
+ // Stores
const { initLightBox, LightBoxComponent } = useLightBox();
+ const { getLegendCollapsedFromOrderedLayerInfo, setLegendCollapsed } = useMapStoreActions();
- // Get store actions
- const highlightedLayer = useLayerHighlightedLayer();
- const { getVisibilityFromOrderedLayerInfo, setOrToggleLayerVisibility, getLegendCollapsedFromOrderedLayerInfo, setLegendCollapsed } =
- useMapStoreActions();
- const { setHighlightLayer, zoomToLayerExtent } = useLayerStoreActions();
-
- const getLayerChildren = (): TypeLegendLayer[] => {
- return layer.children?.filter((c) => ['processed', 'loaded'].includes(c.layerStatus ?? ''));
- };
-
- /**
- * Handle expand/shrink of layer groups.
- */
- const handleExpandGroupClick = (): void => {
- setLegendCollapsed(layer.layerPath);
- };
-
- /**
- * Set the layer visivbility on the map
- * @param {React.MouseEvent} e Mouse event
- */
- const handleToggleVisibility = (e: React.MouseEvent): void => {
- e.stopPropagation();
- setOrToggleLayerVisibility(layer.layerPath);
- };
-
- /**
- * Set the highlight feature on the map for a layer
- * @param {React.MouseEvent} e Mouse event
- */
- const handleHighlightLayer = (e: React.MouseEvent): void => {
- e.stopPropagation();
- setHighlightLayer(layer.layerPath);
- };
-
- /**
- * Set the zoom on the map based on the layer path
- * @param {React.MouseEvent} e Mouse event
- */
- const handleZoomTo = (e: React.MouseEvent): void => {
- e.stopPropagation();
- zoomToLayerExtent(layer.layerPath).catch((error) => {
- // Log
- logger.logPromiseFailed('in zoomToLayerExtent in legend-layer.handleZoomTo', error);
- });
- };
-
- const legendExpanded = !getLegendCollapsedFromOrderedLayerInfo(layer.layerPath);
-
- const visibility = !getVisibilityFromOrderedLayerInfo(layer.layerPath);
- const isLayerVisible = layer.controls?.visibility ?? false;
-
- const getSecondaryText = (): JSX.Element => {
- // dnt show icons when layer status is not loaded
- if (!['processed', 'loaded'].includes(layer.layerStatus ?? '')) {
- return ;
- }
- let subTitle = '';
- if (getLayerChildren().length) {
- subTitle = t('legend.subLayersCount').replace('{count}', getLayerChildren().length.toString());
- } else if (layer.items.length > 1) {
- subTitle = t('legend.itemsCount')
- .replace('{count}', layer.items.length.toString())
- .replace('{totalCount}', layer.items.length.toString());
- }
- return (
-
- {!!subTitle.length && {subTitle}}
-
- handleToggleVisibility(e)}
- disabled={!isLayerVisible}
- >
- {visibility ? : }
-
- handleHighlightLayer(e)}
- >
- {highlightedLayer === layer.layerPath ? : }
-
- handleZoomTo(e)}>
-
-
-
-
- );
- };
-
- // renders the layers children, if any
- function renderChildren(): JSX.Element | null {
- if (!layer.children?.length) {
- return null;
- }
-
- return (
-
- {layer.children
- .filter((d) => !['error', 'processing'].includes(d.layerStatus ?? ''))
- .map((item) => (
-
- ))}
-
- );
- }
-
- // renders the layers items if any
- function renderItems(): JSX.Element | null {
- if (!layer.items?.length) {
- return null;
- }
- return (
-
- {layer.items.map((item) => (
-
- {item.icon ? : }
-
-
-
-
- ))}
-
- );
- }
-
- function renderCollapsible(): JSX.Element | null {
- if (
- layer.type === CV_CONST_LAYER_TYPES.WMS &&
- layer.icons.length &&
- layer.icons[0].iconImage &&
- layer.icons[0].iconImage !== 'no data'
- ) {
- const imgSrc = layer.icons[0].iconImage;
- return (
-
- initLightBox(imgSrc, '', 0, 2)}
- onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter' ? initLightBox(imgSrc, '', 0, 2) : null)}
- />
-
- );
- }
+ // Memoized values
+ const layerChildren = useMemo(
+ () => layer.children?.filter((c) => ['processed', 'loaded'].includes(c.layerStatus ?? '')) ?? [],
+ [layer.children]
+ );
- // show sub items only when number of items are more than 1.
- if (!(layer.children?.length > 1 || layer.items?.length > 1)) {
- return null;
- }
+ const [legendExpanded, setLegendExpanded] = useState(getLegendCollapsedFromOrderedLayerInfo(layer.layerPath));
- return (
-
- {renderChildren()}
- {renderItems()}
-
- );
- }
+ const handleExpandGroupClick = useCallback(
+ (e: React.MouseEvent): void => {
+ e.stopPropagation();
+ setLegendCollapsed(layer.layerPath);
+ setLegendExpanded(getLegendCollapsedFromOrderedLayerInfo(layer.layerPath));
+ },
+ [layer.layerPath, setLegendCollapsed]
+ );
return (
-
+ <>
<>
@@ -223,7 +60,14 @@ export function LegendLayer({ layer }: LegendLayerProps): JSX.Element {
primary={layer.layerName}
className="layerTitle"
disableTypography
- secondary={getSecondaryText()}
+ secondary={
+
+ }
/>
{!!(layer.children?.length > 1 || layer.items?.length > 1) && (
@@ -233,9 +77,17 @@ export function LegendLayer({ layer }: LegendLayerProps): JSX.Element {
)}
>
-
- {renderCollapsible()}
-
-
+
+ {LightBoxComponent}
+ >
);
-}
+});
+
+export default LegendLayer;