From c69036c5a951413388bc4b20c910208e4f533f79 Mon Sep 17 00:00:00 2001 From: Mateusz Kwasniewski Date: Tue, 27 Aug 2024 15:47:55 +0200 Subject: [PATCH] feat: new in unleash tooltip (#7991) --- .../FeatureLifecycleTooltip.tsx | 2 +- .../NewInUnleash/NewInUnleash.tsx | 83 +++++++---- .../NewInUnleash/NewInUnleashItem.tsx | 79 ++++++++--- .../NewInUnleash/NewInUnleashTooltip.tsx | 129 ++++++++++++++++++ 4 files changed, 245 insertions(+), 48 deletions(-) create mode 100644 frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx diff --git a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx index 9f262a51cf..46d597c98d 100644 --- a/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx +++ b/frontend/src/component/feature/FeatureView/FeatureOverview/FeatureLifecycle/FeatureLifecycleTooltip.tsx @@ -105,7 +105,7 @@ const StageBox = styled(Box, { const ColorFill = styled(Box)(({ theme }) => ({ backgroundColor: theme.palette.primary.light, color: theme.palette.primary.contrastText, - borderRadius: theme.spacing(0, 0, 1, 1), // has to match the parent tooltip container + borderRadius: `0 0 ${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px`, // has to match the parent tooltip container margin: theme.spacing(-1, -1.5), // has to match the parent tooltip container padding: theme.spacing(2, 3), })); diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx index 754b019ed7..f94cb8c028 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleash.tsx @@ -12,7 +12,6 @@ import { styled, } from '@mui/material'; import Signals from '@mui/icons-material/Sensors'; -import { useNavigate } from 'react-router-dom'; import type { NavigationMode } from 'component/layout/MainLayout/NavigationSidebar/NavigationMode'; import { NewInUnleashItem } from './NewInUnleashItem'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; @@ -71,7 +70,9 @@ type NewItem = { label: string; icon: ReactNode; link: string; + docsLink: string; show: boolean; + longDescription: ReactNode; }; interface INewInUnleashProps { @@ -86,7 +87,6 @@ export const NewInUnleash = ({ onMiniModeClick, }: INewInUnleashProps) => { const { trackEvent } = usePlausibleTracker(); - const navigate = useNavigate(); const [seenItems, setSeenItems] = useLocalStorageState( 'new-in-unleash-seen:v1', new Set(), @@ -99,7 +99,35 @@ export const NewInUnleash = ({ label: 'Signals & Actions', icon: , link: '/integrations/signals', + docsLink: 'https://docs.getunleash.io/reference/signals', show: isEnterprise() && signalsEnabled, + longDescription: ( + <> +

+ It allows you to respond to events in your real-time + monitoring system by automating tasks such as disabling + a beta feature in response to an increase in errors or a + drop in conversion rates. +

+ +

+

+

+ + ), }, ]; @@ -135,31 +163,32 @@ export const NewInUnleash = ({ New in Unleash - {visibleItems.map(({ label, icon, link }) => ( - { - trackEvent('new-in-unleash-click', { - props: { - label, - }, - }); - navigate(link); - onItemClick?.(); - }} - onDismiss={() => { - trackEvent('new-in-unleash-dismiss', { - props: { - label, - }, - }); - setSeenItems(new Set([...seenItems, label])); - }} - > - {label} - - ))} + {visibleItems.map( + ({ label, icon, link, longDescription, docsLink }) => ( + { + trackEvent('new-in-unleash-click', { + props: { + label, + }, + }); + }} + onDismiss={() => { + trackEvent('new-in-unleash-dismiss', { + props: { + label, + }, + }); + setSeenItems(new Set([...seenItems, label])); + }} + label={label} + icon={icon} + link={link} + longDescription={longDescription} + docsLink={docsLink} + /> + ), + )} ); diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx index 93cc126540..4384ad5e63 100644 --- a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashItem.tsx @@ -1,12 +1,14 @@ -import type { ReactNode } from 'react'; +import type * as React from 'react'; +import { type ReactNode, useState } from 'react'; import { IconButton, ListItem, ListItemButton, - Tooltip, styled, + Tooltip, } from '@mui/material'; import Close from '@mui/icons-material/Close'; +import { NewInUnleashTooltip } from './NewInUnleashTooltip'; const StyledItemButton = styled(ListItemButton)(({ theme }) => ({ justifyContent: 'space-between', @@ -30,37 +32,74 @@ interface INewInUnleashItemProps { icon: ReactNode; onClick: () => void; onDismiss: () => void; - children: ReactNode; + label: string; + longDescription: ReactNode; + link: string; + docsLink: string; } +const useTooltip = () => { + const [open, setOpen] = useState(false); + + const handleTooltipClose = () => { + setOpen(false); + }; + + const handleTooltipOpen = () => { + setOpen(true); + }; + + return { open, handleTooltipOpen, handleTooltipClose }; +}; + export const NewInUnleashItem = ({ icon, onClick, onDismiss, - children, + label, + longDescription, + link, + docsLink, }: INewInUnleashItemProps) => { + const { open, handleTooltipOpen, handleTooltipClose } = useTooltip(); + const onDismissClick = (e: React.MouseEvent) => { e.stopPropagation(); onDismiss(); }; return ( - - - - {icon} - {children} - - - - - - - + { + onClick(); + handleTooltipOpen(); + }} + > + + + + {icon} + {label} + + + + + + + + ); }; diff --git a/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx new file mode 100644 index 0000000000..1a07f6145f --- /dev/null +++ b/frontend/src/component/layout/MainLayout/NavigationSidebar/NewInUnleash/NewInUnleashTooltip.tsx @@ -0,0 +1,129 @@ +import type * as React from 'react'; +import type { FC, ReactNode } from 'react'; +import { HtmlTooltip } from 'component/common/HtmlTooltip/HtmlTooltip'; +import { + Box, + Button, + Link, + styled, + Typography, + ClickAwayListener, +} from '@mui/material'; +import { type Link as RouterLink, useNavigate } from 'react-router-dom'; +import OpenInNew from '@mui/icons-material/OpenInNew'; +import { ReactComponent as UnleashLogo } from 'assets/img/logoWithWhiteText.svg'; + +const Header = styled(Box)(({ theme }) => ({ + backgroundColor: theme.palette.primary.light, + color: theme.palette.primary.contrastText, + borderRadius: `${theme.shape.borderRadiusMedium}px ${theme.shape.borderRadiusMedium}px 0 0`, // has to match the parent tooltip container + margin: theme.spacing(-1, -1.5), // has to match the parent tooltip container + padding: theme.spacing(2, 3), + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + minHeight: '120px', +})); + +const Body = styled(Box)(({ theme }) => ({ + padding: theme.spacing(2), +})); + +const StyledLink = styled(Link)(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), + padding: 0, + color: theme.palette.links, + fontWeight: theme.fontWeight.medium, + '&:hover, &:focus': { + textDecoration: 'underline', + }, +})); + +const StyledOpenInNew = styled(OpenInNew)(({ theme }) => ({ + fontSize: theme.spacing(2.25), +})); + +const StyledUnleashLogo = styled(UnleashLogo)({ width: '150px' }); + +const LongDescription = styled(Box)(({ theme }) => ({ + ul: { + paddingLeft: theme.spacing(2), + }, +})); + +const Title = styled(Typography)(({ theme }) => ({ + margin: theme.spacing(2, 0), +})); + +const ReadMore = styled(Box)(({ theme }) => ({ + margin: theme.spacing(3, 0), +})); + +export const NewInUnleashTooltip: FC<{ + children: React.ReactElement; + title: string; + longDescription: ReactNode; + docsLink: string; + link: string; + open: boolean; + onClose: () => void; +}> = ({ children, title, longDescription, link, docsLink, open, onClose }) => { + const navigate = useNavigate(); + + return ( + + +
+ +
+ + {title} + {longDescription} + + + Read more in our + documentation + + + + +
+ + } + > + {children} +
+ ); +};