diff --git a/services/web/frontend/js/features/project-list/components/notifications/ads/inr-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/ads/inr-banner.tsx index 35d6ad34ed..fc4944a2ff 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/ads/inr-banner.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/ads/inr-banner.tsx @@ -96,14 +96,16 @@ export default function INRBanner({ variant, splitTestName }: INRBannerProps) { if (variant === 'default') { return ( - - + ]} // eslint-disable-line react/jsx-key /> - - + } + action={ - - + } + /> ) } else if (variant === 'green-banner') { return ( - - + ,
]} // eslint-disable-line react/jsx-key @@ -126,17 +130,18 @@ export default function INRBanner({ variant, splitTestName }: INRBannerProps) { shouldUnescape tOptions={{ interpolation: { escapeValue: true } }} /> -
- + } + action={ - -
+ } + /> ) } else if (variant === 'modal') { return ( diff --git a/services/web/frontend/js/features/project-list/components/notifications/ads/latam-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/ads/latam-banner.tsx index d36fb876e1..76ca9ca951 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/ads/latam-banner.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/ads/latam-banner.tsx @@ -83,8 +83,10 @@ export default function LATAMBanner() { } = LATAM_CURRENCIES[currency as keyof typeof LATAM_CURRENCIES] return ( - handleDismiss()}> - + handleDismiss()} + body={ ]} // eslint-disable-line react/jsx-key @@ -92,8 +94,8 @@ export default function LATAMBanner() { shouldUnescape tOptions={{ interpolation: { escapeValue: true } }} /> - - + } + action={ - - + } + /> ) } diff --git a/services/web/frontend/js/features/project-list/components/notifications/groups-and-enterprise-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/groups-and-enterprise-banner.tsx index 59e3c0c7fc..154098ba79 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/groups-and-enterprise-banner.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/groups-and-enterprise-banner.tsx @@ -62,11 +62,11 @@ export default function GroupsAndEnterpriseBanner() { } return ( - - - - - + } + action={ {t('contact_sales')} - - + } + /> ) } diff --git a/services/web/frontend/js/features/project-list/components/notifications/notification.tsx b/services/web/frontend/js/features/project-list/components/notifications/notification.tsx index 868c0eb5c6..979b3c74ed 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/notification.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/notification.tsx @@ -4,21 +4,44 @@ import Body from './body' import Action from './action' import Close from '../../../../shared/components/close' import classnames from 'classnames' +import NewNotification, { + NotificationType, +} from '@/shared/components/notification' +import getMeta from '@/utils/meta' type NotificationProps = { bsStyle: AlertProps['bsStyle'] - children: React.ReactNode + children?: React.ReactNode + body?: React.ReactNode + action?: React.ReactElement onDismiss?: AlertProps['onDismiss'] className?: string } +/** + * Renders either a legacy-styled notification using Boostrap `Alert`, or a new-styled notification using + * the shared `Notification` component. + * + * The content of the notification is provided either with `children` (keeping backwards compatibility), + * or a `body` prop (along with an optional `action`). + * + * When the content is provided via `body` prop the notification is rendered with the new Notification component + * if `ol-newNotificationStyle` meta is set to true. + */ function Notification({ bsStyle, children, onDismiss, className, + body, + action, ...props }: NotificationProps) { + const newNotificationStyle = getMeta( + 'ol-newNotificationStyle', + false + ) as boolean + const [show, setShow] = useState(true) const handleDismiss = () => { @@ -33,18 +56,49 @@ function Notification({ return null } - return ( -
  • - - {children} - {onDismiss ? ( -
    - -
    - ) : null} -
    -
  • - ) + if (newNotificationStyle && body) { + const newNotificationType = ( + bsStyle === 'danger' ? 'error' : bsStyle + ) as NotificationType + return ( + + ) + } + + if (body) { + return ( +
  • + + {body} + {action && {action}} + {onDismiss ? ( +
    + +
    + ) : null} +
    +
  • + ) + } else { + return ( +
  • + + {children} + {onDismiss ? ( +
    + +
    + ) : null} +
    +
  • + ) + } } Notification.Body = Body diff --git a/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx b/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx index 32b9a65ebc..6c41ce7646 100644 --- a/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx +++ b/services/web/frontend/js/features/project-list/components/notifications/writefull-promo-banner.tsx @@ -41,15 +41,14 @@ function WritefullPromoBanner({ bsStyle="info" onDismiss={handleClose} className="centered-alert" - > - + body={ Get 10% off Writefull premium—AI-based language feedback and TeXGPT to help you write great papers faster. Use code:{' '} OVERLEAF10 - - + } + action={ Get Writefull for Overleaf - - + } + /> ) } diff --git a/services/web/frontend/js/shared/components/notification.tsx b/services/web/frontend/js/shared/components/notification.tsx index cf36dfc8f0..30a35c812c 100644 --- a/services/web/frontend/js/shared/components/notification.tsx +++ b/services/web/frontend/js/shared/components/notification.tsx @@ -3,7 +3,7 @@ import React, { ReactElement, useState } from 'react' import { useTranslation } from 'react-i18next' import MaterialIcon from './material-icon' -type NotificationType = 'info' | 'success' | 'warning' | 'error' +export type NotificationType = 'info' | 'success' | 'warning' | 'error' type NotificationProps = { action?: React.ReactElement