diff --git a/packages/geoview-core/src/api/config/types/config-constants.ts b/packages/geoview-core/src/api/config/types/config-constants.ts index a93792b4e96..cf16bc5459f 100644 --- a/packages/geoview-core/src/api/config/types/config-constants.ts +++ b/packages/geoview-core/src/api/config/types/config-constants.ts @@ -178,3 +178,8 @@ export const CV_DEFAULT_LAYER_INITIAL_SETTINGS = { queryable: false, }, }; + +/** + * Definition of the default order of the tabs inside appbar + */ +export const CV_DEFAULT_APPBAR_TABS_ORDER = ['legend', 'details', 'guide']; diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts index dbef3057ef0..2abcdec9bc5 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/feature-info-event-processor.ts @@ -140,8 +140,13 @@ export class FeatureInfoEventProcessor extends AbstractEventProcessor { // If there was some features on this propagation if (atLeastOneFeature) { // If the current tab is not 'details' nor 'geochart', switch to details - if (!['details', 'geochart'].includes(UIEventProcessor.getActiveFooterBarTab(mapId))) + if (!['details', 'geochart'].includes(UIEventProcessor.getActiveFooterBarTab(mapId))) { UIEventProcessor.setActiveFooterBarTab(mapId, 'details'); + } + + if (UIEventProcessor.getActiveAppBarTabId(mapId) !== 'AppbarPanelButtonDetails') { + UIEventProcessor.setActiveAppBarTabId(mapId, 'AppbarPanelButtonDetails'); + } } } diff --git a/packages/geoview-core/src/api/event-processors/event-processor-children/ui-event-processor.ts b/packages/geoview-core/src/api/event-processors/event-processor-children/ui-event-processor.ts index 79b6a54a607..eec837f18ef 100644 --- a/packages/geoview-core/src/api/event-processors/event-processor-children/ui-event-processor.ts +++ b/packages/geoview-core/src/api/event-processors/event-processor-children/ui-event-processor.ts @@ -39,6 +39,10 @@ export class UIEventProcessor extends AbstractEventProcessor { return this.getUIState(mapId).activeFooterBarTabId; } + static getActiveAppBarTabId(mapId: string): string { + return this.getUIState(mapId).activeAppBarTabId; + } + static getAppBarComponents(mapId: string): TypeValidAppBarCoreProps { return this.getUIState(mapId).appBarComponents; } @@ -56,4 +60,8 @@ export class UIEventProcessor extends AbstractEventProcessor { static setActiveFooterBarTab(mapId: string, id: string): void { this.getUIState(mapId).setterActions.setActiveFooterBarTab(id); } + + static setActiveAppBarTabId(mapId: string, id: string): void { + this.getUIState(mapId).setterActions.setActiveAppBarTabId(id); + } } diff --git a/packages/geoview-core/src/core/components/app-bar/app-bar.tsx b/packages/geoview-core/src/core/components/app-bar/app-bar.tsx index 733f38e654a..b3034e15bea 100644 --- a/packages/geoview-core/src/core/components/app-bar/app-bar.tsx +++ b/packages/geoview-core/src/core/components/app-bar/app-bar.tsx @@ -9,8 +9,8 @@ import { Plugin } from '@/api/plugin/plugin'; import { TypeButtonPanel, TypePanelProps } from '@/ui/panel/panel-types'; import ExportButton from '@/core/components/export/export-modal-button'; import { + useUIActiveAppBarTabId, useUIActiveFocusItem, - useUIActiveFooterBarTabId, useUIAppbarComponents, useUIAppbarGeolocatorActive, useUIStoreActions, @@ -28,6 +28,7 @@ import { getSxClasses } from './app-bar-style'; import { enforceArrayOrder, helpCloseAll, helpClosePanelById, helpOpenPanelById } from './app-bar-helper'; import { TypeJsonObject, TypeJsonValue, toJsonObject } from '@/core/types/global-types'; import { AbstractPlugin } from '@/api/plugin/abstract-plugin'; +import { CV_DEFAULT_APPBAR_TABS_ORDER } from '@/api/config/types/config-constants'; interface GroupPanelType { icon: ReactNode; @@ -56,7 +57,6 @@ export function AppBar(props: AppBarProps): JSX.Element { // internal component state const [buttonPanelGroups, setButtonPanelGroups] = useState>>({}); - const [selectedAppBarButtonId, setSelectedAppbarButtonId] = useState(''); const appBar = useRef(null); // get store values and action @@ -64,11 +64,10 @@ export function AppBar(props: AppBarProps): JSX.Element { const interaction = useMapInteraction(); const appBarComponents = useUIAppbarComponents(); const { hideClickMarker } = useMapStoreActions(); + const activeAppBarTabId = useUIActiveAppBarTabId(); const geoviewElement = useAppGeoviewHTMLElement().querySelector('[id^="mapTargetElement-"]') as HTMLElement; - // TODO: remove active footerTab Id and create new one for AppBar id. - const activeFooterTabId = useUIActiveFooterBarTabId(); - const { setGeolocatorActive } = useUIStoreActions(); + const { setGeolocatorActive, setActiveAppBarTabId } = useUIStoreActions(); const isGeolocatorActive = useUIAppbarGeolocatorActive(); // get store config for app bar to add (similar logic as in footer-bar) @@ -106,9 +105,9 @@ export function AppBar(props: AppBarProps): JSX.Element { // Redirect to helper helpClosePanelById(mapId, buttonPanelGroups, buttonId, groupName, setButtonPanelGroups, focusWhenNoElementCallback); - setSelectedAppbarButtonId(''); + setActiveAppBarTabId(''); }, - [buttonPanelGroups, geoviewElement, mapId] + [buttonPanelGroups, geoviewElement, mapId, setActiveAppBarTabId] ); const closeAll = useCallback(() => { @@ -126,9 +125,9 @@ export function AppBar(props: AppBarProps): JSX.Element { // Redirect to helper helpOpenPanelById(buttonPanelGroups, buttonId, groupName, setButtonPanelGroups, closeAll); - setSelectedAppbarButtonId(buttonId); + setActiveAppBarTabId(buttonId); }, - [buttonPanelGroups, closeAll] + [buttonPanelGroups, closeAll, setActiveAppBarTabId] ); const handleButtonClicked = useCallback( @@ -157,11 +156,11 @@ export function AppBar(props: AppBarProps): JSX.Element { const handleGeneralCloseClicked = useCallback(() => { // Log - logger.logTraceUseCallback('APP-BAR - handleGeneralCloseClicked', selectedAppBarButtonId); + logger.logTraceUseCallback('APP-BAR - handleGeneralCloseClicked', activeAppBarTabId); // Close it - closePanelById(selectedAppBarButtonId, undefined); - }, [selectedAppBarButtonId, closePanelById]); + closePanelById(activeAppBarTabId, undefined); + }, [activeAppBarTabId, closePanelById]); const handleAddButtonPanel = useCallback( (sender: AppBarApi, event: AppBarCreatedEvent) => { @@ -218,9 +217,8 @@ export function AppBar(props: AppBarProps): JSX.Element { useEffect(() => { // Log logger.logTraceUseEffect('APP-BAR - open detail panel when clicked on map', mapId); - // TODO: remove active footerTab Id and create new one for AppBar id. // open AppBar detail drawer when click on map. - if (activeFooterTabId === 'details' && buttonPanelGroups?.details?.AppbarPanelButtonDetails?.panel) { + if (activeAppBarTabId === 'AppbarPanelButtonDetails' && buttonPanelGroups?.details?.AppbarPanelButtonDetails?.panel) { // close geolocator when user click on map layer. if (isGeolocatorActive) { setGeolocatorActive(false); @@ -229,7 +227,7 @@ export function AppBar(props: AppBarProps): JSX.Element { openPanelById(buttonPanelGroups?.details?.AppbarPanelButtonDetails?.button?.id || '', undefined); } // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeFooterTabId]); + }, [activeAppBarTabId]); /** * Create default tabs from configuration parameters (similar logic as in footer-bar). @@ -268,7 +266,7 @@ export function AppBar(props: AppBarProps): JSX.Element { // render footer bar tabs (appBarConfig?.tabs.core ?? []) - .filter((tab) => tab === 'guide' || tab === 'details' || tab === 'legend') + .filter((tab) => CV_DEFAULT_APPBAR_TABS_ORDER.includes(tab)) .map((tab): [TypeIconButtonProps, TypePanelProps, string] => { const button: TypeIconButtonProps = { id: `AppbarPanelButton${capitalize(tab)}`, @@ -290,16 +288,29 @@ export function AppBar(props: AppBarProps): JSX.Element { return [button, panel, tab]; }) .forEach((footerGroup) => appBarApi.createAppbarPanel(footerGroup[0], footerGroup[1], footerGroup[2])); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [appBarConfig?.tabs.core, appBarApi]); // Not exhaustive, because it'd be dangerous to trigger on `panels` or on `t`, because of how the AppBar panels are just recreated all the time (should refactor this, maybe..) + }, [appBarConfig?.tabs.core, appBarApi, t, memoPanels]); // #endregion - let buttonPanelGroupNames = Object.keys(buttonPanelGroups); - buttonPanelGroupNames = enforceArrayOrder(buttonPanelGroupNames, ['legend', 'details', 'guide']); - const topGroupNames = buttonPanelGroupNames.filter((groupName) => groupName !== 'guide'); - const bottomGroupNames = buttonPanelGroupNames.filter((groupName) => groupName === 'guide'); + /** + * Re-order the appbar buttons. + */ + const { topGroupNames, bottomGroupNames } = useMemo(() => { + // Log + logger.logTraceUseMemo('APP-BAR - panels'); + + let buttonPanelGroupNames = Object.keys(buttonPanelGroups); + buttonPanelGroupNames = enforceArrayOrder(buttonPanelGroupNames, CV_DEFAULT_APPBAR_TABS_ORDER); + const topGroup = buttonPanelGroupNames.filter((groupName) => groupName !== 'guide'); + const bottomGroup = buttonPanelGroupNames.filter((groupName) => groupName === 'guide'); + return { topGroupNames: topGroup, bottomGroupNames: bottomGroup }; + }, [buttonPanelGroups]); + /** + * Render Tab groups in appbar. + * @param {string[]} groupNames group that will be rendered in appbar. + * @returns JSX.Element + */ const renderButtonGroup = (groupNames: string[]): ReactNode => { return ( <> @@ -320,9 +331,9 @@ export function AppBar(props: AppBarProps): JSX.Element { aria-label={buttonPanel.button.tooltip} tooltip={buttonPanel.button.tooltip} tooltipPlacement="right" - className={`style3 ${selectedAppBarButtonId === buttonPanel.button.id ? 'active' : ''}`} + className={`style3 ${activeAppBarTabId === buttonPanel.button.id ? 'active' : ''}`} size="small" - onClick={(): void => handleButtonClicked(buttonPanel.button.id!, groupName)} + onClick={() => handleButtonClicked(buttonPanel.button.id!, groupName)} > {buttonPanel.button.children} diff --git a/packages/geoview-core/src/core/components/attribution/attribution.tsx b/packages/geoview-core/src/core/components/attribution/attribution.tsx index 77b8322d31c..7e65059e29c 100644 --- a/packages/geoview-core/src/core/components/attribution/attribution.tsx +++ b/packages/geoview-core/src/core/components/attribution/attribution.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useCallback, useState } from 'react'; import { useTheme } from '@mui/material/styles'; @@ -30,17 +30,15 @@ export function Attribution(): JSX.Element { // getStore value const mapAttribution = useMapAttribution(); + const expanded = useUIMapInfoExpanded(); - const handleOpenPopover = (event: React.MouseEvent): void => { + const handleOpenPopover = useCallback((event: React.MouseEvent): void => { setAnchorEl(event.currentTarget); - }; + }, []); - const handleClosePopover = (): void => { + const handleClosePopover = useCallback(() => { setAnchorEl(null); - }; - - // get store value - const expanded = useUIMapInfoExpanded(); + }, []); return ( <> @@ -52,9 +50,9 @@ export function Attribution(): JSX.Element { tooltip="mapctrl.attribution.tooltip" sx={{ color: theme.palette.geoViewColor.bgColor.light[800], - marginTop: expanded ? '12px' : '4px', + marginTop: expanded ? '0.75rem' : '0.25rem', [theme.breakpoints.up('md')]: { - marginTop: expanded ? '23px' : 'none', + marginTop: expanded ? '1.4375rem' : 'none', }, width: '30px', height: '30px', @@ -77,7 +75,7 @@ export function Attribution(): JSX.Element { }} onClose={handleClosePopover} > - + {mapAttribution.map((attribution) => { return {attribution}; })} diff --git a/packages/geoview-core/src/core/components/common/full-screen-dialog.tsx b/packages/geoview-core/src/core/components/common/full-screen-dialog.tsx index 20b375dfe46..1fdb070c7ce 100644 --- a/packages/geoview-core/src/core/components/common/full-screen-dialog.tsx +++ b/packages/geoview-core/src/core/components/common/full-screen-dialog.tsx @@ -8,9 +8,7 @@ interface FullScreenDialogProps extends DialogProps { children: ReactNode; } -function FullScreenDialog(props: FullScreenDialogProps): JSX.Element { - const { open, onClose, children } = props; - +function FullScreenDialog({ open, onClose, children }: FullScreenDialogProps): JSX.Element { return ( diff --git a/packages/geoview-core/src/core/components/common/layer-list.tsx b/packages/geoview-core/src/core/components/common/layer-list.tsx index 1bdfe67a82c..7ecd9434eda 100644 --- a/packages/geoview-core/src/core/components/common/layer-list.tsx +++ b/packages/geoview-core/src/core/components/common/layer-list.tsx @@ -1,4 +1,4 @@ -import { ReactNode, memo } from 'react'; +import { ReactNode, memo, useCallback } from 'react'; import { useTheme } from '@mui/material/styles'; import { useTranslation } from 'react-i18next'; import { animated, useSpring } from '@react-spring/web'; @@ -48,55 +48,49 @@ const LayerListItem = memo(function LayerListItem({ isSelected, layer, onListIte layer.layerStatus === 'loading' || layer.layerStatus === 'processing'; + /** + * Render Layer Icon based on layerPath + * @returns + */ const renderLayerIcon = (): JSX.Element | null => { - switch (layer.layerStatus) { - case 'error': - return null; - - default: - // If there is content, this is a guide section with no icon - if (layer.content) return null; - // If there's a layer path - if (layer.layerPath) { - return ( - - ); - } - return null; + if (layer.layerPath) { + return ( + + ); } + return null; }; - const renderLayerStatus = (): JSX.Element | string | null => { - switch (layer.layerStatus) { - case 'error': - return t('legend.layerError'); - - default: - switch (layer.queryStatus) { - case 'init': - case 'processing': - return `${t('layers.querying')}...`; - case 'error': - return t('legend.layerError'); - default: - return ( - <> - {layer.layerFeatures} {layer?.mapFilteredIcon ?? ''} - - ); - } + /** + * Get layer status based on query status and layer status + */ + const getLayerStatus = useCallback((): JSX.Element | string => { + if (layer.layerStatus === 'error' || layer?.queryStatus === 'error') { + return `${t('legend.layerError')}`; } - }; + if (['init', 'processing'].includes(layer.queryStatus)) { + return `${t('layers.querying')}...`; + } + return ( + <> + {layer.layerFeatures} {layer?.mapFilteredIcon ?? ''} + + ); + }, [layer, t]); + /** + * Render Layer body. + * @returns JSX.Element + */ const renderLayerBody = (): JSX.Element => { return ( {layer.layerName} - {renderLayerStatus()} + {getLayerStatus()} @@ -119,9 +113,15 @@ const LayerListItem = memo(function LayerListItem({ isSelected, layer, onListIte to: { opacity: 1 }, }); - const handleLayerKeyDown = (e: React.KeyboardEvent, selectedLayer: LayerListEntry): void => { - if (e.key === 'Enter') onListItemClick(selectedLayer); - }; + /** + * Handle layer click when mouse enter is pressed. + */ + const handleLayerKeyDown = useCallback( + (e: React.KeyboardEvent, selectedLayer: LayerListEntry): void => { + if (e.key === 'Enter') onListItemClick(selectedLayer); + }, + [onListItemClick] + ); const AnimatedPaper = animated(Paper); diff --git a/packages/geoview-core/src/core/components/common/layout.tsx b/packages/geoview-core/src/core/components/common/layout.tsx index bfd4ad07cda..26b4fb19ff3 100644 --- a/packages/geoview-core/src/core/components/common/layout.tsx +++ b/packages/geoview-core/src/core/components/common/layout.tsx @@ -1,4 +1,4 @@ -import { useCallback, ReactNode, useRef } from 'react'; +import { useCallback, ReactNode, useRef, useMemo } from 'react'; import { logger } from '@/core/utils/logger'; import { LayerList, LayerListEntry } from './layer-list'; import { ResponsiveGridLayout, ResponsiveGridLayoutExposedMethods } from './responsive-grid-layout'; @@ -53,13 +53,24 @@ export function Layout({ return ; }, [selectedLayerPath, layerList, handleLayerChange]); - const renderLayerTitle = (): JSX.Element => { + /** + * Get the layer title + */ + const memoLayerTitle = useMemo(() => { + return layerList.find((layer) => layer.layerPath === selectedLayerPath)?.layerName ?? ''; + }, [layerList, selectedLayerPath]); + + /** + * Render layer title + * @returns JSX.Element + */ + const renderLayerTitle = useCallback((): JSX.Element => { return ( - {layerList.find((layer) => layer.layerPath === selectedLayerPath)?.layerName ?? ''} + {memoLayerTitle} ); - }; + }, [fullWidth, memoLayerTitle]); return ( ) => { @@ -76,8 +76,7 @@ const ResponsiveGridLayout = forwardRef( useEffect(() => { onGuideIsOpen?.(isGuideOpen); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [isGuideOpen]); // TODO: Check - Try to add the dependency on `onGuideIsOpen` here, making it a useCallback if necessary and test + }, [isGuideOpen, onGuideIsOpen]); useEffect(() => { // if hideEnlargeBtn changes to true and isEnlarged is true, set isEnlarged to false @@ -105,11 +104,11 @@ const ResponsiveGridLayout = forwardRef( [onIsEnlargeClicked] ); - const handleOpenGuide = (): void => { + const handleOpenGuide = useCallback((): void => { if (guideContentIds) { setIsGuideOpen(true); } - }; + }, [setIsGuideOpen, guideContentIds]); // If we're on mobile if (theme.breakpoints.down('md')) { @@ -331,17 +330,5 @@ const ResponsiveGridLayout = forwardRef( ResponsiveGridLayout.displayName = 'ResponsiveGridLayout'; -// TODO: Refactor - Remove defaultProps as it's no longer a good practice -ResponsiveGridLayout.defaultProps = { - leftTop: null, - leftMain: null, - rightTop: null, - fullWidth: false, - guideContentIds: [], - onIsEnlargeClicked: undefined, - hideEnlargeBtn: false, - onGuideIsOpen: undefined, -}; - export { ResponsiveGridLayout }; export type { ResponsiveGridLayoutExposedMethods }; diff --git a/packages/geoview-core/src/core/components/common/responsive-grid.tsx b/packages/geoview-core/src/core/components/common/responsive-grid.tsx index c68ab27e6a5..5ab6ab93e87 100644 --- a/packages/geoview-core/src/core/components/common/responsive-grid.tsx +++ b/packages/geoview-core/src/core/components/common/responsive-grid.tsx @@ -56,7 +56,15 @@ const getLeftPanelSize = (fullWidth: boolean, isRightPanelVisible: boolean, isEn */ const ResponsiveGridLeftPanel = forwardRef( ( - { children, className, isRightPanelVisible = false, sxProps = {}, isEnlarged, fullWidth = false, ...rest }: ResponsiveGridPanelProps, + { + children, + className = '', + isRightPanelVisible = false, + sxProps = {}, + isEnlarged, + fullWidth = false, + ...rest + }: ResponsiveGridPanelProps, ref ) => { const theme = useTheme(); @@ -111,7 +119,15 @@ const getRightPanelSize = (fullWidth: boolean, isRightPanelVisible: boolean, isE */ const ResponsiveGridRightPanel = forwardRef( ( - { children, className, isRightPanelVisible = false, sxProps = {}, isEnlarged, fullWidth = false, ...rest }: ResponsiveGridPanelProps, + { + children, + className = '', + isRightPanelVisible = false, + sxProps = {}, + isEnlarged, + fullWidth = false, + ...rest + }: ResponsiveGridPanelProps, ref ) => { const theme = useTheme(); @@ -143,17 +159,3 @@ export const ResponsiveGrid = { Left: ResponsiveGridLeftPanel, Right: ResponsiveGridRightPanel, }; - -// TODO: Refactor - Remove defaultProps as it's no longer a good practice -ResponsiveGridLeftPanel.defaultProps = { - sxProps: undefined, - fullWidth: false, - className: '', -}; - -// TODO: Refactor - Remove defaultProps as it's no longer a good practice -ResponsiveGridRightPanel.defaultProps = { - sxProps: undefined, - fullWidth: false, - className: '', -}; diff --git a/packages/geoview-core/src/core/components/common/use-footer-panel-height.tsx b/packages/geoview-core/src/core/components/common/use-footer-panel-height.tsx index 8ecdc927131..701d0f2105f 100644 --- a/packages/geoview-core/src/core/components/common/use-footer-panel-height.tsx +++ b/packages/geoview-core/src/core/components/common/use-footer-panel-height.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useRef } from 'react'; +import { RefObject, useCallback, useEffect, useRef } from 'react'; import { useAppFullscreenActive } from '@/core/stores/store-interface-and-intial-values/app-state'; import { useUIActiveFooterBarTabId, useUIFooterPanelResizeValue } from '@/core/stores/store-interface-and-intial-values/ui-state'; import { useDetailsLayerDataArray } from '@/core/stores/store-interface-and-intial-values/feature-info-state'; @@ -11,17 +11,22 @@ import { TABS } from '@/core/utils/constant'; import { useGeoViewMapId } from '@/core/stores/geoview-store'; interface UseFooterPanelHeightType { - footerPanelTab: 'layers' | 'details' | 'data-table' | 'legend' | 'default' | 'guide'; + footerPanelTab: 'legend' | 'default'; +} + +interface UseFooterPanelHeightReturnType { + leftPanelRef: RefObject; + rightPanelRef: RefObject; + panelTitleRef: (node: HTMLDivElement) => void; + activeFooterBarTabId: string; } /** * Custom Hook to calculate the height of footer panel content when we set the map in fullscreen mode. - * @param {'layers' | 'details' | 'datatable' | 'legend'} footerPanelTab type of footer tab. - * @returns {any} An object of ref objects that are attached to DOM. + * @param {'legend' | 'default'} footerPanelTab type of footer tab. + * @returns {UseFooterPanelHeightReturnType} An object of ref objects that are attached to DOM. */ -// ? I doubt we want to define an explicit type for that utility hook? -// eslint-disable-next-line @typescript-eslint/no-explicit-any -export function useFooterPanelHeight({ footerPanelTab }: UseFooterPanelHeightType): any { +export function useFooterPanelHeight({ footerPanelTab = 'default' }: UseFooterPanelHeightType): UseFooterPanelHeightReturnType { const defaultHeight = 600; const mapId = useGeoViewMapId(); diff --git a/packages/geoview-core/src/core/components/crosshair/crosshair.tsx b/packages/geoview-core/src/core/components/crosshair/crosshair.tsx index 78888cca5ad..2d7b32e3133 100644 --- a/packages/geoview-core/src/core/components/crosshair/crosshair.tsx +++ b/packages/geoview-core/src/core/components/crosshair/crosshair.tsx @@ -21,12 +21,10 @@ type CrosshairProps = { * @param {CrosshairProps} - Crossahir props who caintain the mapTargetELement * @returns {JSX.Element} the crosshair component */ -export function Crosshair(props: CrosshairProps): JSX.Element { +export function Crosshair({ mapTargetElement }: CrosshairProps): JSX.Element { // Log logger.logTraceRender('components/crosshair/crosshair'); - const { mapTargetElement } = props; - const { t } = useTranslation(); const theme = useTheme(); @@ -98,14 +96,7 @@ export function Crosshair(props: CrosshairProps): JSX.Element { }, [isCrosshairsActive, mapTargetElement, simulateClick, managePanDelta]); return ( - + diff --git a/packages/geoview-core/src/core/components/data-table/data-panel.tsx b/packages/geoview-core/src/core/components/data-table/data-panel.tsx index 04c3ebc25da..639c93b72c7 100644 --- a/packages/geoview-core/src/core/components/data-table/data-panel.tsx +++ b/packages/geoview-core/src/core/components/data-table/data-panel.tsx @@ -30,7 +30,7 @@ interface DataPanelType { * @returns {JSX.Element} Data table as react element. */ -export function Datapanel({ fullWidth }: DataPanelType): JSX.Element { +export function Datapanel({ fullWidth = false }: DataPanelType): JSX.Element { const { t } = useTranslation(); const theme = useTheme(); @@ -191,11 +191,14 @@ export function Datapanel({ fullWidth }: DataPanelType): JSX.Element { return null; }; - const handleGuideIsOpen = (guideIsOpen: boolean): void => { - if (guideIsOpen) { - setSelectedLayerPath(''); - } - }; + const handleGuideIsOpen = useCallback( + (guideIsOpen: boolean): void => { + if (guideIsOpen) { + setSelectedLayerPath(''); + } + }, + [setSelectedLayerPath] + ); const memoLayerList = useMemo(() => { // Log @@ -230,8 +233,3 @@ export function Datapanel({ fullWidth }: DataPanelType): JSX.Element { ); } - -// TODO: Refactor - Remove defaultProps as it's no longer a good practice -Datapanel.defaultProps = { - fullWidth: false, -}; diff --git a/packages/geoview-core/src/core/components/details/details-panel.tsx b/packages/geoview-core/src/core/components/details/details-panel.tsx index 4b82cf89f0e..ad87a44a921 100644 --- a/packages/geoview-core/src/core/components/details/details-panel.tsx +++ b/packages/geoview-core/src/core/components/details/details-panel.tsx @@ -370,11 +370,14 @@ export function DetailsPanel({ fullWidth = false }: DetailsPanelType): JSX.Eleme resetCurrentIndex(); } - const handleGuideIsOpen = (guideIsOpenVal: boolean): void => { - if (guideIsOpenVal) { - setSelectedLayerPath(''); - } - }; + const handleGuideIsOpen = useCallback( + (guideIsOpenVal: boolean): void => { + if (guideIsOpenVal) { + setSelectedLayerPath(''); + } + }, + [setSelectedLayerPath] + ); /** * Select the layer after layer is selected from map. diff --git a/packages/geoview-core/src/core/components/layers/layers-panel.tsx b/packages/geoview-core/src/core/components/layers/layers-panel.tsx index 0254f7dfb9e..9fe5643bc34 100644 --- a/packages/geoview-core/src/core/components/layers/layers-panel.tsx +++ b/packages/geoview-core/src/core/components/layers/layers-panel.tsx @@ -1,4 +1,4 @@ -import { useRef } from 'react'; +import { useRef, useCallback } from 'react'; import { useTheme } from '@mui/material'; import { Box } from '@/ui'; import { useLayerDisplayState, useLayerStoreActions, useSelectedLayer } from '@/core/stores/store-interface-and-intial-values/layer-state'; @@ -85,11 +85,14 @@ export function LayersPanel(): JSX.Element { ); }; - const handleGuideIsOpen = (guideIsOpen: boolean): void => { - if (guideIsOpen) { - setSelectedLayerPath(''); - } - }; + const handleGuideIsOpen = useCallback( + (guideIsOpen: boolean): void => { + if (guideIsOpen) { + setSelectedLayerPath(''); + } + }, + [setSelectedLayerPath] + ); return ( void; openModal: (uiFocus: FocusItemProps) => void; setActiveFooterBarTab: (id: string) => void; + setActiveAppBarTabId: (id: string) => void; setActiveTrapGeoView: (active: boolean) => void; setGeolocatorActive: (active: boolean) => void; setFooterPanelResizeValue: (value: number) => void; @@ -40,6 +42,7 @@ export interface IUIState { closeModal: () => void; openModal: (uiFocus: FocusItemProps) => void; setActiveFooterBarTab: (id: string) => void; + setActiveAppBarTabId: (id: string) => void; setActiveTrapGeoView: (active: boolean) => void; setGeolocatorActive: (active: boolean) => void; setFooterPanelResizeValue: (value: number) => void; @@ -52,6 +55,7 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat const init = { appBarComponents: ['geolocator'], activeFooterBarTabId: 'legend', + activeAppBarTabId: '', activeTrapGeoView: false, corePackagesComponents: [], focusITem: { activeElementId: false, callbackElementId: false }, @@ -87,6 +91,10 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat // Redirect to setter get().uiState.setterActions.setActiveFooterBarTab(id); }, + setActiveAppBarTabId: (id: string) => { + // Redirect to setter + get().uiState.setterActions.setActiveAppBarTabId(id); + }, setActiveTrapGeoView: (active: boolean) => { // Redirect to setter get().uiState.setterActions.setActiveTrapGeoView(active); @@ -135,6 +143,14 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat }, }); }, + setActiveAppBarTabId: (id: string) => { + set({ + uiState: { + ...get().uiState, + activeAppBarTabId: id, + }, + }); + }, setActiveTrapGeoView: (active: boolean) => { set({ uiState: { @@ -187,6 +203,7 @@ export function initializeUIState(set: TypeSetStore, get: TypeGetStore): IUIStat // ********************************************************** export const useUIActiveFocusItem = (): FocusItemProps => useStore(useGeoViewStore(), (state) => state.uiState.focusITem); export const useUIActiveFooterBarTabId = (): string => useStore(useGeoViewStore(), (state) => state.uiState.activeFooterBarTabId); +export const useUIActiveAppBarTabId = (): string => useStore(useGeoViewStore(), (state) => state.uiState.activeAppBarTabId); export const useUIActiveTrapGeoView = (): boolean => useStore(useGeoViewStore(), (state) => state.uiState.activeTrapGeoView); export const useUIAppbarComponents = (): TypeValidAppBarCoreProps => useStore(useGeoViewStore(), (state) => state.uiState.appBarComponents); export const useUIAppbarGeolocatorActive = (): boolean => useStore(useGeoViewStore(), (state) => state.uiState.geoLocatorActive); diff --git a/packages/geoview-geochart/src/geochart-panel.tsx b/packages/geoview-geochart/src/geochart-panel.tsx index 05f6fafe520..16368e60770 100644 --- a/packages/geoview-geochart/src/geochart-panel.tsx +++ b/packages/geoview-geochart/src/geochart-panel.tsx @@ -234,11 +234,14 @@ export function GeoChartPanel(props: GeoChartPanelProps): JSX.Element { ); }; - const handleGuideIsOpen = (guideIsOpen: boolean): void => { - if (guideIsOpen) { - setSelectedLayerPath(''); - } - }; + const handleGuideIsOpen = useCallback( + (guideIsOpen: boolean): void => { + if (guideIsOpen) { + setSelectedLayerPath(''); + } + }, + [setSelectedLayerPath] + ); /** * Renders the complete GeoChart Panel component diff --git a/packages/geoview-time-slider/src/time-slider-panel.tsx b/packages/geoview-time-slider/src/time-slider-panel.tsx index d6fb9bd4e94..e3e362f28be 100644 --- a/packages/geoview-time-slider/src/time-slider-panel.tsx +++ b/packages/geoview-time-slider/src/time-slider-panel.tsx @@ -110,11 +110,14 @@ export function TimeSliderPanel(props: TypeTimeSliderProps): JSX.Element { } }, [memoLayersList, selectedLayerPath]); - const handleGuideIsOpen = (guideIsOpen: boolean): void => { - if (guideIsOpen) { - setSelectedLayerPath(''); - } - }; + const handleGuideIsOpen = useCallback( + (guideIsOpen: boolean): void => { + if (guideIsOpen) { + setSelectedLayerPath(''); + } + }, + [setSelectedLayerPath] + ); return (