Skip to content

Commit

Permalink
fix children vis-expand
Browse files Browse the repository at this point in the history
  • Loading branch information
jolevesq committed Dec 16, 2024
1 parent 65f23d2 commit 82e5f48
Show file tree
Hide file tree
Showing 8 changed files with 330 additions and 285 deletions.
12 changes: 12 additions & 0 deletions packages/geoview-core/public/configs/navigator/28-geocore.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@
{
"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"
}
]
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,70 +1,74 @@
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 (
<Collapse in={legendExpanded} sx={sxClasses.collapsibleContainer} timeout="auto">
<Box
component="img"
tabIndex={0}
src={imgSrc}
sx={{ maxWidth: '100%', cursor: 'pointer' }}
onClick={() => initLightBox(imgSrc, '', 0, 2)}
onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter' ? initLightBox(imgSrc, '', 0, 2) : null)}
/>
</Collapse>
);
}

// if (!(childLayers?.length > 1 || items?.length > 1)) {
// return null;
// }

// TODO: childslayers always empty... seems to be use for items
return (
<Collapse in={legendExpanded} sx={sxClasses.collapsibleContainer} timeout="auto">
{layer.children?.length > 0 && (
<List sx={{ width: '100%', padding: '20px', margin: '20px 0px' }}>
{layer.children
.filter((d) => !['error', 'processing'].includes(d.layerStatus ?? ''))
.map((item) => (
<LegendLayerComponent layer={item} key={item.layerPath} />
))}
</List>
)}
<ItemsList items={items} />
</Collapse>
);
});
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 it is a WMS and there is a legend image, add it with the lightbox handlers
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 (
<Collapse in={legendExpanded} sx={sxClasses.collapsibleContainer} timeout="auto">
<Box
component="img"
tabIndex={0}
src={imgSrc}
sx={{ maxWidth: '100%', cursor: 'pointer' }}
onClick={() => initLightBox(imgSrc, '', 0, 2)}
onKeyDown={(e) => (e.code === 'Space' || e.code === 'Enter' ? initLightBox(imgSrc, '', 0, 2) : null)}
/>
</Collapse>
);
}

// If there is only one item or no childlayer, do not create the component
if (childLayers?.length === 0 && items?.length === 1) {
return null;
}

if (layer.children?.length > 0) layer.children.every((item) => logger.logDebug('TTT item', item.layerPath));

// Render list of items (layer class) or there is a child layer so render a new legend-layer component
return (
<Collapse in={legendExpanded} sx={sxClasses.collapsibleContainer} timeout="auto">
{layer.children?.length > 0 && (
<List sx={{ width: '100%', padding: '20px', margin: '20px 0px' }}>
{layer.children
.filter((d) => !['error', 'processing'].includes(d.layerStatus ?? ''))
.map((item) => (
<LegendLayerComponent layer={item} key={item.layerPath} />
))}
</List>
)}
<ItemsList items={items} />
</Collapse>
);
});
222 changes: 111 additions & 111 deletions packages/geoview-core/src/core/components/legend/legend-layer-ctrl.tsx
Original file line number Diff line number Diff line change
@@ -1,111 +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<HTMLButtonElement>): void => {
e.stopPropagation();
setOrToggleLayerVisibility(layer.layerPath);
setVisibility(getVisibilityFromOrderedLayerInfo(layer.layerPath));
},
[layer.layerPath, setOrToggleLayerVisibility]
);

const handleHighlightLayer = useCallback(
(e: React.MouseEvent<HTMLButtonElement>): void => {
e.stopPropagation();
setHighlightLayer(layer.layerPath);
},
[layer.layerPath, setHighlightLayer]
);

const handleZoomTo = useCallback(
(e: React.MouseEvent<HTMLButtonElement>): 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 <Box />;
}

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 (
<Stack direction="row" alignItems="center" sx={sxClasses.layerStackIcons}>
{!!subTitle.length && <Typography fontSize={14}>{subTitle}</Typography>}
<Box>
<IconButton
edge="end"
tooltip="layers.toggleVisibility"
className="buttonOutline"
onClick={handleToggleVisibility}
disabled={!isLayerVisible}
>
{visibility ? <VisibilityOffOutlinedIcon /> : <VisibilityOutlinedIcon />}
</IconButton>
<IconButton
tooltip="legend.highlightLayer"
sx={{ marginTop: '-0.3125rem' }}
className="buttonOutline"
onClick={handleHighlightLayer}
>
{highlightedLayer === layer.layerPath ? <HighlightIcon /> : <HighlightOutlinedIcon />}
</IconButton>
<IconButton tooltip="legend.zoomTo" className="buttonOutline" onClick={handleZoomTo}>
<ZoomInSearchIcon />
</IconButton>
</Box>
</Stack>
);
});
import { useTheme } from '@mui/material';
import { useCallback, useMemo } 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[];
visibility: boolean;
}

// SecondaryControls component
export function SecondaryControls({ layer, layerStatus, itemsLength, childLayers, visibility }: SecondaryControlsProps): JSX.Element {
// Hooks
const { t } = useTranslation();
const theme = useTheme();
const sxClasses = useMemo(() => getSxClasses(theme), [theme]);

// Stores
const highlightedLayer = useLayerHighlightedLayer();
const { setOrToggleLayerVisibility } = useMapStoreActions();
const { setHighlightLayer, zoomToLayerExtent } = useLayerStoreActions();

// Is button disabled?
const isLayerVisible = layer.controls?.visibility ?? false;

// #region Handlers Callbacks
const handleToggleVisibility = useCallback(
(e: React.MouseEvent<HTMLButtonElement>): void => {
e.stopPropagation();
setOrToggleLayerVisibility(layer.layerPath);
},
[layer.layerPath, setOrToggleLayerVisibility]
);

const handleHighlightLayer = useCallback(
(e: React.MouseEvent<HTMLButtonElement>): void => {
e.stopPropagation();
setHighlightLayer(layer.layerPath);
},
[layer.layerPath, setHighlightLayer]
);

const handleZoomTo = useCallback(
(e: React.MouseEvent<HTMLButtonElement>): 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 <Box />;
}

// Calculate subtitle after the condition
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 (
<Stack direction="row" alignItems="center" sx={sxClasses.layerStackIcons}>
{!!subTitle.length && <Typography fontSize={14}>{subTitle}</Typography>}
<Box sx={sxClasses.subtitle}>
<IconButton
edge="end"
tooltip="layers.toggleVisibility"
className="buttonOutline"
onClick={handleToggleVisibility}
disabled={!isLayerVisible}
>
{visibility ? <VisibilityOutlinedIcon /> : <VisibilityOffOutlinedIcon />}
</IconButton>
<IconButton
tooltip="legend.highlightLayer"
sx={{ marginTop: '-0.3125rem' }}
className="buttonOutline"
onClick={handleHighlightLayer}
>
{highlightedLayer === layer.layerPath ? <HighlightIcon /> : <HighlightOutlinedIcon />}
</IconButton>
<IconButton tooltip="legend.zoomTo" className="buttonOutline" onClick={handleZoomTo}>
<ZoomInSearchIcon />
</IconButton>
</Box>
</Stack>
);
}
Loading

0 comments on commit 82e5f48

Please sign in to comment.