diff --git a/packages/web-app/package.json b/packages/web-app/package.json index 3603a01a2..093d41314 100644 --- a/packages/web-app/package.json +++ b/packages/web-app/package.json @@ -73,16 +73,20 @@ "@babel/runtime": "7.21.0", "@elastic/react-search-ui": "1.17.1", "@elastic/search-ui-app-search-connector": "1.17.1", + "@emotion/cache": "11.11.0", "@emotion/react": "11.10.6", + "@emotion/serialize": "1.1.2", "@emotion/styled": "11.10.6", + "@emotion/utils": "1.2.1", "@fortawesome/fontawesome-svg-core": "6.3.0", "@fortawesome/free-regular-svg-icons": "6.3.0", "@fortawesome/free-solid-svg-icons": "6.3.0", "@fortawesome/react-fontawesome": "0.2.0", - "@novu/notification-center": "0.14.0", - "@saladtechnologies/garden-components": "1.1.5", + "@novu/notification-center": "0.16.2", + "@novu/shared": "0.17.1", + "@saladtechnologies/garden-components": "1.1.8", "@saladtechnologies/garden-fonts": "1.0.3", - "@saladtechnologies/garden-icons": "1.0.11", + "@saladtechnologies/garden-icons": "1.0.12", "@storybook/addon-a11y": "6.5.16", "@storybook/addon-actions": "6.5.16", "@storybook/addon-essentials": "6.5.16", diff --git a/packages/web-app/src/App.tsx b/packages/web-app/src/App.tsx index 7911279ba..9a18fffb6 100644 --- a/packages/web-app/src/App.tsx +++ b/packages/web-app/src/App.tsx @@ -12,6 +12,7 @@ import { MobileDevice, NotMobile } from './components' import { config } from './config' import { MobileRoutes } from './MobileRoutes' import { NavigationBarContainer } from './modules/home-views' +import { NovuNotificationBanner } from './modules/notifications-views/components' import { Routes } from './Routes' import type { SaladTheme } from './SaladTheme' import { getStore } from './Store' @@ -117,8 +118,11 @@ export const App = withStyles(styles)( public override render(): ReactNode { const { classes, history } = this.props + const isAuthenticated = this.store.auth.isAuthenticated + return ( <> + {isAuthenticated && }
diff --git a/packages/web-app/src/components/NovuProviderWrapper/NovuProviderWrapper.tsx b/packages/web-app/src/components/NovuProviderWrapper/NovuProviderWrapper.tsx index 0edc801b0..7bee5dd6b 100644 --- a/packages/web-app/src/components/NovuProviderWrapper/NovuProviderWrapper.tsx +++ b/packages/web-app/src/components/NovuProviderWrapper/NovuProviderWrapper.tsx @@ -8,12 +8,10 @@ interface NovuProviderWrapperProps { children: ReactElement } -const isNovuProviderEnabled = false - export const NovuProviderWrapper = observer(({ children }: NovuProviderWrapperProps): ReactElement | null => { const store = getStore() const { currentProfile } = store.profile - if (currentProfile?.id && isNovuProviderEnabled) { + if (currentProfile?.id) { return ( { const isAuthenticated = store.auth.isAuthenticated @@ -25,6 +26,12 @@ const mapStoreToProps = (store: RootStore): any => { canBeRedeemed: store.balance.currentBalance >= store.rewards.selectedTargetReward?.price, } : null + const isNotificationsDrawerOpened = store.notifications.isNotificationsDrawerOpened + const notifications = { + isNotificationsDrawerOpened, + onOpenNotificationsDrawer: store.notifications.openNotificationsDrawer, + onCloseNotificationsDrawer: store.notifications.closeNotificationsDrawer, + } const goToAccount = () => store.routing.push('/account/summary') const goToSelectTargetRewardPage = () => store.routing.push('/store/select-target-reward') @@ -74,7 +81,8 @@ const mapStoreToProps = (store: RootStore): any => { startButtonToolTipError: startButton.toolTipError, username: isAuthenticated ? store.profile.currentProfile?.username : undefined, targetReward, + notifications, } } -export const NavigationBarContainer = connect(mapStoreToProps, NavigationBar) +export const NavigationBarContainer = connect(mapStoreToProps, NavigationBarWithNotifications) diff --git a/packages/web-app/src/modules/home-views/components/NavigationBarWithNotifications.tsx b/packages/web-app/src/modules/home-views/components/NavigationBarWithNotifications.tsx new file mode 100644 index 000000000..386bfc218 --- /dev/null +++ b/packages/web-app/src/modules/home-views/components/NavigationBarWithNotifications.tsx @@ -0,0 +1,38 @@ +import { useNotifications } from '@novu/notification-center' +import { NavigationBar, type NavigationBarProps } from '@saladtechnologies/garden-components' +import type { FunctionComponent } from 'react' +import { getConfiguredNovuBannerNotifications } from '../../notifications/utils' + +export const NavigationBarWithNotifications: FunctionComponent = (props) => { + const { + notifications: novuNotifications, + unseenCount, + markNotificationAsRead, + markAllNotificationsAsSeen, + } = useNotifications() + + const unreadNovuNotifications = novuNotifications?.filter((notification) => !notification.read) + const bannerNotifications = getConfiguredNovuBannerNotifications(unreadNovuNotifications, (notificationId: string) => + markNotificationAsRead(notificationId), + ) + const newsNotifications = bannerNotifications.filter((notification) => notification?.variant === 'news') + const warningsNotifications = bannerNotifications.filter((notification) => notification?.variant === 'error') + const hasUnseenNotifications = unseenCount > 0 + const handleOpenNotificationsDrawer = () => { + props.notifications.onOpenNotificationsDrawer() + + if (hasUnseenNotifications) { + markAllNotificationsAsSeen() + } + } + + const notifications = { + ...props.notifications, + news: newsNotifications, + warnings: warningsNotifications, + hasUnseenNotifications, + onOpenNotificationsDrawer: handleOpenNotificationsDrawer, + } + + return +} diff --git a/packages/web-app/src/modules/notifications/components/NotificationToast.stories.tsx b/packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.stories.tsx similarity index 96% rename from packages/web-app/src/modules/notifications/components/NotificationToast.stories.tsx rename to packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.stories.tsx index 6833deef1..a9a3fa7a0 100644 --- a/packages/web-app/src/modules/notifications/components/NotificationToast.stories.tsx +++ b/packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.stories.tsx @@ -1,6 +1,6 @@ import { action } from '@storybook/addon-actions' import { storiesOf } from '@storybook/react' -import { addStories } from '../../../../.storybook/addStories' +import { addStories } from '../../../../../.storybook/addStories' import { NotificationToast } from './NotificationToast' const stories = [ diff --git a/packages/web-app/src/modules/notifications/components/NotificationToast.tsx b/packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.tsx similarity index 95% rename from packages/web-app/src/modules/notifications/components/NotificationToast.tsx rename to packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.tsx index 292c296f6..010182187 100644 --- a/packages/web-app/src/modules/notifications/components/NotificationToast.tsx +++ b/packages/web-app/src/modules/notifications-views/components/NotificationToast/NotificationToast.tsx @@ -5,8 +5,8 @@ import type { ReactNode } from 'react' import { Component } from 'react' import type { WithStyles } from 'react-jss' import withStyles from 'react-jss' -import { P } from '../../../components' -import type { SaladTheme } from '../../../SaladTheme' +import { P } from '../../../../components' +import type { SaladTheme } from '../../../../SaladTheme' const styles = (theme: SaladTheme) => ({ container: { diff --git a/packages/web-app/src/modules/notifications-views/components/NotificationToast/index.tsx b/packages/web-app/src/modules/notifications-views/components/NotificationToast/index.tsx new file mode 100644 index 000000000..d01a8106f --- /dev/null +++ b/packages/web-app/src/modules/notifications-views/components/NotificationToast/index.tsx @@ -0,0 +1 @@ +export * from './NotificationToast' diff --git a/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/NovuNotificationBanner.tsx b/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/NovuNotificationBanner.tsx new file mode 100644 index 000000000..4a5d4c481 --- /dev/null +++ b/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/NovuNotificationBanner.tsx @@ -0,0 +1,53 @@ +import { useNotifications } from '@novu/notification-center' +import { NotificationBanner } from '@saladtechnologies/garden-components' +import type { FC } from 'react' +import { useEffect, useState } from 'react' +import type { WithStyles } from 'react-jss' +import withStyles from 'react-jss' +import { getConfiguredNovuBannerNotifications } from '../../../notifications/utils' + +const styles = () => ({ + container: { + width: 560, + position: 'fixed', + zIndex: 99, + top: 85, + left: 0, + right: 0, + margin: 'auto', + }, +}) + +interface NovuNotificationBannerRawProps extends WithStyles {} + +export const NovuNotificationBannerRaw: FC = ({ classes }) => { + const { notifications, markNotificationAsRead } = useNotifications() + const [isHidden, setisHidden] = useState(false) + + const unreadNovuNotifications = notifications?.filter((notification) => !notification.read) + const bannerNotifications = getConfiguredNovuBannerNotifications( + unreadNovuNotifications, + (notificationId: string) => { + markNotificationAsRead(notificationId) + setisHidden(true) + }, + ) + const overlayNovuNotifications = bannerNotifications?.filter((notification) => notification.overlay) + const lastOverlayNovuNotification = overlayNovuNotifications[0] + + useEffect(() => { + setisHidden(false) + }, [notifications, setisHidden]) + + if (!lastOverlayNovuNotification || isHidden) { + return null + } + + return ( +
+ +
+ ) +} + +export const NovuNotificationBanner = withStyles(styles)(NovuNotificationBannerRaw) diff --git a/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/index.tsx b/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/index.tsx new file mode 100644 index 000000000..739b58636 --- /dev/null +++ b/packages/web-app/src/modules/notifications-views/components/NovuNotificationBanner/index.tsx @@ -0,0 +1 @@ +export * from './NovuNotificationBanner' diff --git a/packages/web-app/src/modules/notifications-views/components/index.tsx b/packages/web-app/src/modules/notifications-views/components/index.tsx new file mode 100644 index 000000000..d15a10965 --- /dev/null +++ b/packages/web-app/src/modules/notifications-views/components/index.tsx @@ -0,0 +1,2 @@ +export * from './NotificationToast' +export * from './NovuNotificationBanner' diff --git a/packages/web-app/src/modules/notifications/NotificationStore.tsx b/packages/web-app/src/modules/notifications/NotificationStore.tsx index 27cac2c6c..2bc10f6d3 100644 --- a/packages/web-app/src/modules/notifications/NotificationStore.tsx +++ b/packages/web-app/src/modules/notifications/NotificationStore.tsx @@ -1,11 +1,25 @@ +import { action, observable } from 'mobx' import { toast } from 'react-toastify' import type { RootStore } from '../../Store' -import { NotificationToast } from './components/NotificationToast' +import { NotificationToast } from '../notifications-views/components' import type { NotificationMessage } from './models' export class NotificationStore { + @observable + public isNotificationsDrawerOpened: boolean = false + constructor(private readonly store: RootStore) {} + @action.bound + openNotificationsDrawer = () => { + this.isNotificationsDrawerOpened = true + } + + @action.bound + closeNotificationsDrawer = () => { + this.isNotificationsDrawerOpened = false + } + /** * Shows a notification to the user * @param message The notification message diff --git a/packages/web-app/src/modules/notifications/models/NotificationMessage.tsx b/packages/web-app/src/modules/notifications/models/NotificationMessage.tsx index 3113e6e39..6ff496254 100644 --- a/packages/web-app/src/modules/notifications/models/NotificationMessage.tsx +++ b/packages/web-app/src/modules/notifications/models/NotificationMessage.tsx @@ -12,6 +12,8 @@ export enum NotificationMessageCategory { ReferralCodeInvalid = 'Referral Code Invalid', ReferralCodeDoesNotExist = 'Referral Code Does Not Exist', ReferralCodeError = 'Referral Code Error', + NovuInfo = 'Novu Info', + NovuWarning = 'Novu Warning', } export interface NotificationMessage { @@ -52,3 +54,63 @@ export interface NotificationMessage { */ onClick?: () => void } + +/** A resource that represents an action that acknowledges a notification. */ +export interface AcknowledgeNotificationAction { + /** The title. */ + title: string +} +/** A resource that represents an action that dismisses a notification. */ +export interface DismissNotificationAction { + /** The title. */ + title: string +} +/** A resource that represents an action that opens a link in the default browser. */ +export interface OpenLinkNotificationAction { + /** The title. */ + title: string + /** The link. */ + link: string +} + +/** A resource that represents an in-app notification action. */ +export interface NotificationAction { + action?: + | { + $case: 'acknowledge' + acknowledge: AcknowledgeNotificationAction + } + | { + $case: 'dismiss' + dismiss: DismissNotificationAction + } + | { + $case: 'openLink' + openLink: OpenLinkNotificationAction + } +} + +export interface Notification { + /** The Novu resource identifier. */ + novuId: string + /** The title. */ + title: string + /** The body. */ + body: string + /** The date and time of the notification. */ + createDate: Date | undefined + /** The list of actions. */ + actions: NotificationAction[] + /** A value indicating whether the notification has been acknowledged. */ + acknowledged: boolean + /** identifier used to track actions from this notification. */ + trackId: string + /** A value indicating whether the notification is os type. */ + osNotification: boolean + /** A value indicating whether the notification is overlay type. */ + overlay: boolean + /** A value indicating whether the notification has been seen. */ + seen: boolean + /** A value indicating whether the notification has been read. */ + read: boolean +} diff --git a/packages/web-app/src/modules/notifications/utils.tsx b/packages/web-app/src/modules/notifications/utils.tsx new file mode 100644 index 000000000..2e62afb01 --- /dev/null +++ b/packages/web-app/src/modules/notifications/utils.tsx @@ -0,0 +1,182 @@ +import type { IMessage } from '@novu/shared' +import type { NotificationBannerProps as GardenNotificationBannerProps } from '@saladtechnologies/garden-components' +import { DateTime } from 'luxon' +import { NotificationMessageCategory, type Notification, type NotificationAction } from './models' + +interface NovuTemplateCta { + acknowledgeLabel: string + linkCTA: { + linkLabel: string + url: string + } +} + +type NovuTemplateCtaContent = NovuTemplateCta['acknowledgeLabel'] | NovuTemplateCta['linkCTA'] +type NotificationBannerProps = GardenNotificationBannerProps & { + overlay: boolean +} + +const getNormalizedNotificationAction = ( + ctaKey: string, + ctaContent: NovuTemplateCtaContent, +): NotificationAction['action'] => { + switch (ctaKey) { + case 'linkCTA': { + return { + $case: 'openLink', + openLink: { + link: (ctaContent as NovuTemplateCta['linkCTA']).url, + title: (ctaContent as NovuTemplateCta['linkCTA']).linkLabel, + }, + } + } + case 'acknowledgeLabel': + default: { + return { + $case: 'acknowledge', + acknowledge: { + title: ctaContent as NovuTemplateCta['acknowledgeLabel'], + }, + } + } + } +} + +export interface IMessageWithId extends IMessage { + id: string +} + +export const getNormalizedNovuNotification = (novuNotification: IMessage): Notification | null => { + try { + const { v1, osNotification, overlay } = JSON.parse(novuNotification.content as string) + + const { cta } = v1 + + const actions: NotificationAction[] = Object.keys(cta).map((key: string) => { + return { action: getNormalizedNotificationAction(key, cta[key]) } + }) + + const trackId = v1.type === 'info' ? NotificationMessageCategory.NovuInfo : NotificationMessageCategory.NovuWarning + + return { + trackId, + novuId: novuNotification._id, + title: v1.title, + body: v1.body, + read: novuNotification.read, + seen: novuNotification.seen, + createDate: new Date(novuNotification.createdAt), + acknowledged: novuNotification.read, + actions, + overlay, + osNotification, + } + } catch (e) { + return null + } +} + +interface NotificationActionPayload { + label: string + onClick: () => void +} + +const getReceivedAtDisplay = ( + createDate: Date, +): { value: number; unit: 'year' | 'month' | 'day' | 'hour' | 'minute' | 'second' } => { + const createDateLuxon = DateTime.fromJSDate(createDate) + const duration = DateTime.now().diff(createDateLuxon) + const interval = duration.shiftTo('years', 'months', 'days', 'hours', 'minutes', 'seconds').toObject() + if (interval.years !== undefined && interval.years >= 1) { + return { value: interval.years, unit: 'year' } + } + if (interval.months !== undefined && interval.months >= 1) { + return { value: interval.months, unit: 'month' } + } + if (interval.days !== undefined && interval.days >= 1) { + return { value: interval.days, unit: 'day' } + } + if (interval.hours !== undefined && interval.hours >= 1) { + return { value: interval.hours, unit: 'hour' } + } + if (interval.minutes !== undefined && interval.minutes >= 1) { + return { value: Math.ceil(interval.minutes), unit: 'minute' } + } + + return { value: interval.seconds ? Math.ceil(interval.seconds) : 0, unit: 'second' } +} + +const getNotificationBannerAction = ( + notification: Notification, + onReadNovuNotification: (notificationId: string) => void, + action?: NotificationAction, +): NotificationActionPayload => { + switch (action?.action?.$case) { + case 'acknowledge': { + return { + label: action.action.acknowledge.title, + onClick: () => onReadNovuNotification(notification.novuId), + } + } + case 'dismiss': { + return { + label: action.action.dismiss.title, + onClick: () => onReadNovuNotification(notification.novuId), + } + } + case 'openLink': { + const openLink = action.action.openLink + + return { + label: openLink.title, + onClick: () => { + window.open(openLink.link, '_blank') + onReadNovuNotification(notification.novuId) + }, + } + } + default: + return { + label: '', + // eslint-disable-next-line @typescript-eslint/no-empty-function + onClick: () => {}, + } + } +} + +export const getConfiguredNovuBannerNotifications = ( + novuNotifications: IMessage[] | undefined, + onReadNovuNotification: (notificationId: string) => void, +): NotificationBannerProps[] => { + if (!novuNotifications) { + return [] + } + + const configuredNovuBannerNotifications: (NotificationBannerProps | null)[] = novuNotifications.map( + (notification) => { + const normalizedNotification = getNormalizedNovuNotification(notification) + + if (!normalizedNotification) { + return null + } + + const { createDate, title, body, overlay, trackId, actions, novuId } = normalizedNotification + const firstNotificationAction = actions[0] + const secondNotificationAction = actions[1] + const variant = trackId === NotificationMessageCategory.NovuInfo ? 'news' : 'error' + + return { + action1: getNotificationBannerAction(normalizedNotification, onReadNovuNotification, firstNotificationAction), + action2: getNotificationBannerAction(normalizedNotification, onReadNovuNotification, secondNotificationAction), + message: body, + onClose: () => onReadNovuNotification(novuId), + receivedAt: createDate ? getReceivedAtDisplay(createDate) : { value: 1, unit: 'minute' }, + title, + variant, + overlay, + } + }, + ) + + return configuredNovuBannerNotifications.filter((notification) => notification !== null) as NotificationBannerProps[] +} diff --git a/packages/web-app/yarn.lock b/packages/web-app/yarn.lock index 4d8fac26c..325668f23 100644 --- a/packages/web-app/yarn.lock +++ b/packages/web-app/yarn.lock @@ -1969,6 +1969,19 @@ __metadata: languageName: node linkType: hard +"@emotion/cache@npm:11.11.0": + version: 11.11.0 + resolution: "@emotion/cache@npm:11.11.0" + dependencies: + "@emotion/memoize": ^0.8.1 + "@emotion/sheet": ^1.2.2 + "@emotion/utils": ^1.2.1 + "@emotion/weak-memoize": ^0.3.1 + stylis: 4.2.0 + checksum: 8eb1dc22beaa20c21a2e04c284d5a2630a018a9d51fb190e52de348c8d27f4e8ca4bbab003d68b4f6cd9cc1c569ca747a997797e0f76d6c734a660dc29decf08 + languageName: node + linkType: hard + "@emotion/cache@npm:^11.10.5, @emotion/cache@npm:^11.4.0": version: 11.10.5 resolution: "@emotion/cache@npm:11.10.5" @@ -2015,6 +2028,13 @@ __metadata: languageName: node linkType: hard +"@emotion/hash@npm:^0.9.1": + version: 0.9.1 + resolution: "@emotion/hash@npm:0.9.1" + checksum: 716e17e48bf9047bf9383982c071de49f2615310fb4e986738931776f5a823bc1f29c84501abe0d3df91a3803c80122d24e28b57351bca9e01356ebb33d89876 + languageName: node + linkType: hard + "@emotion/is-prop-valid@npm:^1.2.0": version: 1.2.0 resolution: "@emotion/is-prop-valid@npm:1.2.0" @@ -2031,6 +2051,13 @@ __metadata: languageName: node linkType: hard +"@emotion/memoize@npm:^0.8.1": + version: 0.8.1 + resolution: "@emotion/memoize@npm:0.8.1" + checksum: a19cc01a29fcc97514948eaab4dc34d8272e934466ed87c07f157887406bc318000c69ae6f813a9001c6a225364df04249842a50e692ef7a9873335fbcc141b0 + languageName: node + linkType: hard + "@emotion/react@npm:11.10.6, @emotion/react@npm:^11.8.1": version: 11.10.6 resolution: "@emotion/react@npm:11.10.6" @@ -2073,6 +2100,19 @@ __metadata: languageName: node linkType: hard +"@emotion/serialize@npm:1.1.2": + version: 1.1.2 + resolution: "@emotion/serialize@npm:1.1.2" + dependencies: + "@emotion/hash": ^0.9.1 + "@emotion/memoize": ^0.8.1 + "@emotion/unitless": ^0.8.1 + "@emotion/utils": ^1.2.1 + csstype: ^3.0.2 + checksum: 413c352e657f1b5e27ea6437b3ef7dcc3860669b7ae17fd5c18bfbd44e033af1acc56b64d252284a813ca4f3b3e1b0841c42d3fb08e02d2df56fd3cd63d72986 + languageName: node + linkType: hard + "@emotion/serialize@npm:^1.1.1": version: 1.1.1 resolution: "@emotion/serialize@npm:1.1.1" @@ -2093,6 +2133,13 @@ __metadata: languageName: node linkType: hard +"@emotion/sheet@npm:^1.2.2": + version: 1.2.2 + resolution: "@emotion/sheet@npm:1.2.2" + checksum: d973273c9c15f1c291ca2269728bf044bd3e92a67bca87943fa9ec6c3cd2b034f9a6bfe95ef1b5d983351d128c75b547b43ff196a00a3875f7e1d269793cecfe + languageName: node + linkType: hard + "@emotion/styled@npm:11.10.6": version: 11.10.6 resolution: "@emotion/styled@npm:11.10.6" @@ -2140,6 +2187,13 @@ __metadata: languageName: node linkType: hard +"@emotion/unitless@npm:^0.8.1": + version: 0.8.1 + resolution: "@emotion/unitless@npm:0.8.1" + checksum: 385e21d184d27853bb350999471f00e1429fa4e83182f46cd2c164985999d9b46d558dc8b9cc89975cb337831ce50c31ac2f33b15502e85c299892e67e7b4a88 + languageName: node + linkType: hard + "@emotion/use-insertion-effect-with-fallbacks@npm:^1.0.0": version: 1.0.0 resolution: "@emotion/use-insertion-effect-with-fallbacks@npm:1.0.0" @@ -2149,6 +2203,13 @@ __metadata: languageName: node linkType: hard +"@emotion/utils@npm:1.2.1, @emotion/utils@npm:^1.2.1": + version: 1.2.1 + resolution: "@emotion/utils@npm:1.2.1" + checksum: e0b44be0705b56b079c55faff93952150be69e79b660ae70ddd5b6e09fc40eb1319654315a9f34bb479d7f4ec94be6068c061abbb9e18b9778ae180ad5d97c73 + languageName: node + linkType: hard + "@emotion/utils@npm:^1.2.0": version: 1.2.0 resolution: "@emotion/utils@npm:1.2.0" @@ -2163,6 +2224,13 @@ __metadata: languageName: node linkType: hard +"@emotion/weak-memoize@npm:^0.3.1": + version: 0.3.1 + resolution: "@emotion/weak-memoize@npm:0.3.1" + checksum: b2be47caa24a8122622ea18cd2d650dbb4f8ad37b636dc41ed420c2e082f7f1e564ecdea68122b546df7f305b159bf5ab9ffee872abd0f052e687428459af594 + languageName: node + linkType: hard + "@eslint-community/eslint-utils@npm:^4.2.0": version: 4.2.0 resolution: "@eslint-community/eslint-utils@npm:4.2.0" @@ -2975,26 +3043,26 @@ __metadata: languageName: node linkType: hard -"@novu/client@npm:^0.14.0": - version: 0.14.0 - resolution: "@novu/client@npm:0.14.0" +"@novu/client@npm:^0.16.2": + version: 0.16.4 + resolution: "@novu/client@npm:0.16.4" dependencies: - "@novu/shared": ^0.14.0 - checksum: 68e96b757c59e1cbb734c4e266dd2f9484c4ab2db791969cc891409d4655286dfa121c6d703ae27dac813fd2c7405c1303de5bfcaa21b458bf6b144ee821e36a + "@novu/shared": ^0.16.4 + checksum: e30c597fef39a248e7895edc2581cf36eb37f669f1f3de4283a3429107b8d88daef92926dc41897938087829e82276c2b92e2cdcbc78df3537b5ee17567c8885 languageName: node linkType: hard -"@novu/notification-center@npm:0.14.0": - version: 0.14.0 - resolution: "@novu/notification-center@npm:0.14.0" +"@novu/notification-center@npm:0.16.2": + version: 0.16.2 + resolution: "@novu/notification-center@npm:0.16.2" dependencies: "@emotion/css": ^11.10.5 "@emotion/react": ^11.7.1 "@emotion/styled": ^11.6.0 "@mantine/core": ^5.7.1 "@mantine/hooks": ^5.7.1 - "@novu/client": ^0.14.0 - "@novu/shared": ^0.14.0 + "@novu/client": ^0.16.2 + "@novu/shared": ^0.16.2 "@rollup/plugin-babel": ^6.0.3 "@tanstack/react-query": ^4.20.4 acorn-jsx: ^5.3.2 @@ -3011,18 +3079,29 @@ __metadata: peerDependencies: react: ">=16.8.0" react-dom: ">=16.8.0" - checksum: da7cadeb6bfa85fab7987e17a07435b8fc492e14a9853afe2846d357b9fa07505714c8e6a52b209477afd3d5326801d2fd27eaca4ff47d01f8b8dcc9126836e8 + checksum: 7f6100685750166369933195465473c8b51766f4e742a80df0451ee2a3e09603f5f57d4366992ec319b0ba40975d02a9a810ef7a3f83efad756fda1fda61db20 languageName: node linkType: hard -"@novu/shared@npm:^0.14.0": - version: 0.14.0 - resolution: "@novu/shared@npm:0.14.0" +"@novu/shared@npm:0.17.1": + version: 0.17.1 + resolution: "@novu/shared@npm:0.17.1" + dependencies: + axios: 1.2.0 + class-transformer: 0.5.1 + class-validator: 0.14.0 + checksum: a468ec6dfee156abb8802ae2a347f1d819ef4d45bd263ba6f8d4e3f23d4a86abc8fbd390add884854dd3d000a3d7dad0047addc3037582188b930ca6b761012c + languageName: node + linkType: hard + +"@novu/shared@npm:^0.16.2, @novu/shared@npm:^0.16.4": + version: 0.16.4 + resolution: "@novu/shared@npm:0.16.4" dependencies: axios: 1.2.0 class-transformer: 0.5.1 class-validator: 0.14.0 - checksum: 99a3d464332dec5eeb6ddf2cbfd3dfa36b8284d38e2d2720e3ae11e540b289b0ea1871d1e75792a7574647a3ea41b8ee5e214503463ef8ddcc8e754703a29bfc + checksum: 16f2a082c781c1ef63e7eafab8e1fdf49ef6f0d35d48304fe398f34be2be49b50964388c1be76c433360b33e4f1a64eb639e8a4c596c3a3b61b75d4760565e27 languageName: node linkType: hard @@ -3346,16 +3425,20 @@ __metadata: "@babel/runtime": 7.21.0 "@elastic/react-search-ui": 1.17.1 "@elastic/search-ui-app-search-connector": 1.17.1 + "@emotion/cache": 11.11.0 "@emotion/react": 11.10.6 + "@emotion/serialize": 1.1.2 "@emotion/styled": 11.10.6 + "@emotion/utils": 1.2.1 "@fortawesome/fontawesome-svg-core": 6.3.0 "@fortawesome/free-regular-svg-icons": 6.3.0 "@fortawesome/free-solid-svg-icons": 6.3.0 "@fortawesome/react-fontawesome": 0.2.0 - "@novu/notification-center": 0.14.0 - "@saladtechnologies/garden-components": 1.1.5 + "@novu/notification-center": 0.16.2 + "@novu/shared": 0.17.1 + "@saladtechnologies/garden-components": 1.1.8 "@saladtechnologies/garden-fonts": 1.0.3 - "@saladtechnologies/garden-icons": 1.0.11 + "@saladtechnologies/garden-icons": 1.0.12 "@storybook/addon-a11y": 6.5.16 "@storybook/addon-actions": 6.5.16 "@storybook/addon-essentials": 6.5.16 @@ -3461,9 +3544,9 @@ __metadata: languageName: unknown linkType: soft -"@saladtechnologies/garden-components@npm:1.1.5": - version: 1.1.5 - resolution: "@saladtechnologies/garden-components@npm:1.1.5" +"@saladtechnologies/garden-components@npm:1.1.8": + version: 1.1.8 + resolution: "@saladtechnologies/garden-components@npm:1.1.8" peerDependencies: "@emotion/react": 11.x "@emotion/styled": 11.x @@ -3478,7 +3561,7 @@ __metadata: react-intl: 6.x react-range: 1.x react-responsive: 9.x - checksum: a44be0c688520b814e04ec1e5f93436fbc5c5ac1db286d097f0410f3d9a2eb0d6e22b9145d8437de5c1db85b62db2bbacf433882b2edb5c734453fb873825890 + checksum: 952d7aeb49e50de4a6d9a0916d3707a54ad613cbf0d631f0857188e8401eaf2b5488a14ca92d5bd0038d06a4568daae624722d8068bfb59ee39987969b1f6432 languageName: node linkType: hard @@ -3489,13 +3572,13 @@ __metadata: languageName: node linkType: hard -"@saladtechnologies/garden-icons@npm:1.0.11": - version: 1.0.11 - resolution: "@saladtechnologies/garden-icons@npm:1.0.11" +"@saladtechnologies/garden-icons@npm:1.0.12": + version: 1.0.12 + resolution: "@saladtechnologies/garden-icons@npm:1.0.12" peerDependencies: react: 18.x react-dom: 18.x - checksum: 5ea12a2e484a67c492269e77450ea7d8a8fbe4788cb20482a493b5877c96fb2021bb2ae075ed8ccc87e80c1ef717f35dbf8436aa0684e84304e0ba56d751a981 + checksum: a05b7f49da45af9b2b06c5a38f4ea1710721f7e076db76baca17a0289dacf1806f146522fd6c8dfc91ce67f519e0324fa1ba68ec53874f9eb2c0b836245a4805 languageName: node linkType: hard @@ -21052,6 +21135,13 @@ __metadata: languageName: node linkType: hard +"stylis@npm:4.2.0": + version: 4.2.0 + resolution: "stylis@npm:4.2.0" + checksum: 0eb6cc1b866dc17a6037d0a82ac7fa877eba6a757443e79e7c4f35bacedbf6421fadcab4363b39667b43355cbaaa570a3cde850f776498e5450f32ed2f9b7584 + languageName: node + linkType: hard + "supertokens-js-override@npm:^0.0.4": version: 0.0.4 resolution: "supertokens-js-override@npm:0.0.4"