1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-10-18 11:14:57 +02:00
unleash.unleash/frontend/src/component/banners/Banner/Banner.tsx
Jaanus Sellin ec7bb2dae3
feat: add configurable event for banner goto action (#6603)
We added banner to get attention of customer, but we are not tracking
its usage.
Added a way to track the **goto action** button.
2024-03-19 12:09:09 +02:00

192 lines
5.1 KiB
TypeScript

import Check from '@mui/icons-material/Check';
import ErrorOutlineRounded from '@mui/icons-material/ErrorOutlineRounded';
import InfoOutlined from '@mui/icons-material/InfoOutlined';
import WarningAmber from '@mui/icons-material/WarningAmber';
import { styled, Icon, Link } from '@mui/material';
import { usePlausibleTracker } from 'hooks/usePlausibleTracker';
import { useNavigate } from 'react-router-dom';
import { BannerDialog } from './BannerDialog/BannerDialog';
import { useState } from 'react';
import { Markdown } from 'component/common/Markdown/Markdown';
import type { BannerVariant, IBanner } from 'interfaces/banner';
import { Sticky } from 'component/common/Sticky/Sticky';
const DEFAULT_VARIANT = 'info';
const StyledBar = styled('aside', {
shouldForwardProp: (prop) =>
prop !== 'variant' && prop !== 'inline' && prop !== 'maxHeight',
})<{ variant: BannerVariant; inline?: boolean; maxHeight?: number }>(
({ theme, variant, inline, maxHeight }) => ({
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
padding: theme.spacing(1),
gap: theme.spacing(1),
width: '100%',
...(inline
? {
border: '1px solid',
borderRadius: theme.shape.borderRadiusMedium,
}
: {
borderBottom: '1px solid',
}),
...(maxHeight && {
maxHeight: maxHeight,
overflow: 'auto',
}),
borderColor:
theme.palette[variant]?.border ??
theme.palette[DEFAULT_VARIANT].border,
background:
theme.palette[variant]?.light ??
theme.palette[DEFAULT_VARIANT].light,
color:
theme.palette[variant]?.dark ?? theme.palette[DEFAULT_VARIANT].dark,
fontSize: theme.fontSizes.smallBody,
}),
);
const StyledIcon = styled('div', {
shouldForwardProp: (prop) => prop !== 'variant',
})<{ variant: BannerVariant }>(({ theme, variant }) => ({
display: 'flex',
alignItems: 'center',
color: theme.palette[variant]?.main ?? theme.palette[DEFAULT_VARIANT].main,
}));
interface IBannerProps {
banner: IBanner;
inline?: boolean;
maxHeight?: number;
}
export const Banner = ({ banner, inline, maxHeight }: IBannerProps) => {
const [open, setOpen] = useState(false);
const {
message,
variant = DEFAULT_VARIANT,
sticky,
icon,
link,
linkText = 'More info',
linkClicked,
plausibleEvent,
dialogTitle,
dialog,
} = banner;
const openDialog = () => {
setOpen(true);
linkClicked?.();
};
const bannerBar = (
<StyledBar variant={variant} inline={inline} maxHeight={maxHeight}>
<StyledIcon variant={variant}>
<BannerIcon icon={icon} variant={variant} />
</StyledIcon>
<Markdown>{message}</Markdown>
<BannerButton
link={link}
plausibleEvent={plausibleEvent}
openDialog={openDialog}
>
{linkText}
</BannerButton>
<BannerDialog
open={open}
setOpen={setOpen}
title={dialogTitle || linkText}
>
{dialog!}
</BannerDialog>
</StyledBar>
);
if (sticky) {
return <Sticky>{bannerBar}</Sticky>;
}
return bannerBar;
};
const VariantIcons = {
warning: <WarningAmber />,
info: <InfoOutlined />,
error: <ErrorOutlineRounded />,
success: <Check />,
};
interface IBannerIconProps {
variant: BannerVariant;
icon?: string;
}
const BannerIcon = ({ icon, variant }: IBannerIconProps) => {
if (icon === 'none') return null;
if (icon) return <Icon>{icon}</Icon>;
return VariantIcons[variant] ?? <InfoOutlined />;
};
interface IBannerButtonProps {
link?: string;
plausibleEvent?: string;
openDialog: () => void;
children: React.ReactNode;
}
const BannerButton = ({
link,
plausibleEvent,
openDialog,
children,
}: IBannerButtonProps) => {
const navigate = useNavigate();
const tracker = usePlausibleTracker();
if (!link) return null;
const dialog = link === 'dialog';
const internal = link.startsWith('/');
const trackEvent = () => {
if (!plausibleEvent) return;
tracker.trackEvent('banner', {
props: { event: plausibleEvent },
});
};
if (dialog)
return (
<Link
onClick={() => {
trackEvent();
openDialog();
}}
>
{children}
</Link>
);
if (internal)
return (
<Link
onClick={() => {
trackEvent();
navigate(link);
}}
>
{children}
</Link>
);
return (
<Link href={link} target='_blank' rel='noreferrer' onClick={trackEvent}>
{children}
</Link>
);
};