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