diff --git a/packages/geoview-core/src/core/components/hover-tooltip/hover-tooltip.tsx b/packages/geoview-core/src/core/components/hover-tooltip/hover-tooltip.tsx index 0f0a2ca13bc..d212c1ccf8f 100644 --- a/packages/geoview-core/src/core/components/hover-tooltip/hover-tooltip.tsx +++ b/packages/geoview-core/src/core/components/hover-tooltip/hover-tooltip.tsx @@ -38,8 +38,6 @@ export function HoverTooltip(): JSX.Element | null { const tooltipRef = useRef(null); - - // Update tooltip when store value change from propagation by hover-layer-set to map-event-processor useEffect(() => { // Log @@ -49,7 +47,7 @@ export function HoverTooltip(): JSX.Element | null { setTooltipValue(hoverFeatureInfo!.fieldInfo?.value as string | ''); setTooltipIcon(hoverFeatureInfo!.featureIcon.toDataURL()); setShowTooltip(true); - } + } }, [hoverFeatureInfo]); // clear the tooltip and mouse move and set pixel location @@ -60,13 +58,11 @@ export function HoverTooltip(): JSX.Element | null { setTooltipValue(''); setTooltipIcon(''); setShowTooltip(false); - }, [pointerPosition]); - // Update tooltip position when we have the dimensions of the tooltip useEffect(() => { - if(!mapElem || !tooltipRef.current || !pointerPosition || !pointerPosition.pixel) { + if (!mapElem || !tooltipRef.current || !pointerPosition || !pointerPosition.pixel) { return; } @@ -78,20 +74,17 @@ export function HoverTooltip(): JSX.Element | null { let tooltipY = pointerPosition.pixel[1] - 35; if (pointerPosition.pixel[0] + tooltipRect.width > mapRect.width) { - tooltipX = pointerPosition.pixel[0] - (tooltipRect.width ); + tooltipX = pointerPosition.pixel[0] - tooltipRect.width; } if (pointerPosition.pixel[1] - tooltipRect.height < mapRect.top) { - tooltipY = pointerPosition.pixel[1]+ 10; + tooltipY = pointerPosition.pixel[1] + 10; } tooltipRef.current.style.left = `${tooltipX}px`; tooltipRef.current.style.top = `${tooltipY}px`; - }, [tooltipValue]); - - if (showTooltip && !tooltipValue) { return null; } diff --git a/packages/geoview-core/src/core/components/layers/left-panel/single-layer.tsx b/packages/geoview-core/src/core/components/layers/left-panel/single-layer.tsx index 070e2099890..4dd5eae4393 100644 --- a/packages/geoview-core/src/core/components/layers/left-panel/single-layer.tsx +++ b/packages/geoview-core/src/core/components/layers/left-panel/single-layer.tsx @@ -37,7 +37,6 @@ import { import { LAYER_STATUS } from '@/core/utils/constant'; import { ArrowDownwardIcon, ArrowUpIcon, TableViewIcon } from '@/ui/icons'; import { Divider } from '@/ui/divider/divider'; -import { Box } from '@/ui/layout'; import { Typography } from '@/ui/typography/typography'; interface SingleLayerProps { @@ -125,7 +124,7 @@ export function SingleLayer({ depth, layer, setIsLayersListPanelVisible, index, if (datatableSettings[layer.layerPath]) { return ( - + {itemsLengthDesc}   diff --git a/packages/geoview-core/src/core/components/notifications/notifications.tsx b/packages/geoview-core/src/core/components/notifications/notifications.tsx index dae66dbe8c5..6404514d73b 100644 --- a/packages/geoview-core/src/core/components/notifications/notifications.tsx +++ b/packages/geoview-core/src/core/components/notifications/notifications.tsx @@ -1,8 +1,9 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useTheme } from '@mui/material/styles'; import _ from 'lodash'; import { ClickAwayListener } from '@mui/material'; +import { animated, useSpring } from '@react-spring/web'; import { Box, InfoIcon, @@ -12,6 +13,7 @@ import { CloseIcon, IconButton, NotificationsIcon, + NotificationsActiveIcon, Badge, Typography, Popper, @@ -51,13 +53,30 @@ export default function Notifications(): JSX.Element { // internal state const [anchorEl, setAnchorEl] = useState(null); + const [hasNewNotification, setHasNewNotification] = useState(false); + const [notificationsCount, setNotificationsCount] = useState(0); const [open, setOpen] = useState(false); // get values from the store const notifications = useAppNotifications(); const interaction = useMapInteraction(); const { removeNotification } = useAppStoreActions(); - const notificationsCount = _.sumBy(notifications, (n) => n.count); + + useEffect(() => { + const curNotificationCount = _.sumBy(notifications, (n) => n.count); + if (curNotificationCount > notificationsCount) { + setHasNewNotification(true); + } + setNotificationsCount(curNotificationCount); + }, [notifications, notificationsCount]); + + useEffect(() => { + if (hasNewNotification) { + const timeoutId = setTimeout(() => setHasNewNotification(false), 1000); // Remove after 3 seconds + return () => clearTimeout(timeoutId); + } + return undefined; + }, [hasNewNotification]); // handle open/close const handleOpenPopover = (event: React.MouseEvent): void => { @@ -71,6 +90,17 @@ export default function Notifications(): JSX.Element { } }; + const shakeAnimation = useSpring({ + from: { x: 0, scale: 1 }, + to: async (next) => { + await next({ x: 2 }); // Move 10px right and scale up 10% + await next({ x: -2 }); // Move 10px left and scale down 10% + await next({ x: 0,}); // Reset position and scale + }, + config: { duration: 50 }, // Adjust duration for faster shake + loop: true, + }); + /** * Remove a notification */ @@ -122,7 +152,16 @@ export default function Notifications(): JSX.Element { className={`${interaction === 'dynamic' ? 'style3' : 'style4'} ${open ? 'active' : ''}`} color="primary" > - + {!hasNewNotification &&
} + {hasNewNotification && ( + + + + )}