-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Adds SuitesReminder hook to get a consistent look across platforms for the reminder notification #221
Changes from 11 commits
ea4fbba
6b35c3b
973fe4d
13393bc
fd97683
36cea5f
273bcba
7683342
01f5097
6f8269e
f384697
a6746d0
b75ec62
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,15 @@ | ||
import { type Meta, type StoryObj } from '@storybook/react' | ||
import { expect, screen, userEvent } from '@storybook/test' | ||
import { expect, fn, screen, userEvent } from '@storybook/test' | ||
import React from 'react' | ||
import { Button, Center, GlobalNavigation, Icon, type INavigationCreateProps, Space } from 'src/components' | ||
import { Button, Center, Flex, GlobalNavigation, Icon, type INavigationCreateProps, Space } from 'src/components' | ||
import { Badge } from 'src/components/data-display/Badge/Badge' | ||
import { | ||
type IGlobalNavigationItem, | ||
type IGlobalNavigationLogo, | ||
} from 'src/components/navigation/GlobalNavigation/GlobalNavigationItems' | ||
import { generateOrgs } from 'src/components/navigation/GlobalNavigation/stories-utils' | ||
import { type INavigationOrg } from 'src/components/navigation/GlobalNavigation/WorkspaceSelector/WorkspaceSelectorItems' | ||
import { useSuitesReminder } from 'src/hooks/SuitesReminder/useSuitesReminder' | ||
|
||
const defaultLogo: IGlobalNavigationLogo = { | ||
label: 'Aqua', | ||
|
@@ -995,3 +996,65 @@ export const WorkspaceSearchWithNoResults: Meta<typeof GlobalNavigation> = { | |
await userEvent.type(searchInput, '123{enter}') | ||
}, | ||
} | ||
|
||
export const UseSuitesReminderHook: Story = { | ||
play: async () => { | ||
const alert = fn().mockImplementation(() => {}) | ||
global.alert = alert | ||
|
||
const showNotificationBtn = screen.getByText('Show Notification') | ||
await userEvent.click(showNotificationBtn) | ||
|
||
// Remind me later | ||
const remindMeLaterBtn = await screen.findByText('Remind me later') | ||
await userEvent.click(remindMeLaterBtn) | ||
|
||
await expect(alert).toBeCalledWith('Remind me later') | ||
|
||
// Take me there | ||
await userEvent.click(showNotificationBtn) | ||
|
||
const takeMeThereBtn = await screen.findByText('Take me there') | ||
await userEvent.click(takeMeThereBtn) | ||
|
||
await expect(alert).toBeCalledWith('Take me there') | ||
}, | ||
render: props => { | ||
const [openNotification, contextHolder] = useSuitesReminder({ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh you're so right. I totally forget about it. Will try some 👍🏼 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done! |
||
onClose: () => { | ||
alert('Notification closed') | ||
}, | ||
onRemindMeLater: () => { | ||
alert('Remind me later') | ||
}, | ||
onTakeMeThere: () => { | ||
alert('Take me there') | ||
}, | ||
}) | ||
|
||
return ( | ||
<Flex style={{ minHeight: 800, width: 600, border: '1px solid black' }} justify="space-between" vertical={false}> | ||
tibuurcio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{contextHolder} | ||
<div> | ||
<GlobalNavigation {...props}></GlobalNavigation> | ||
</div> | ||
<Button onClick={openNotification}>Show Notification</Button> | ||
</Flex> | ||
) | ||
}, | ||
args: { | ||
logo: defaultLogo, | ||
tools: defaultTools, | ||
management: defaultManagement, | ||
orgs: defaultOrgs, | ||
navigationButtonItemOptions: { | ||
label: 'Sign Out of mParticle', | ||
onClick: () => { | ||
alert('signing out!') | ||
}, | ||
}, | ||
onMpHomeClick: () => { | ||
alert('Going to mP!') | ||
}, | ||
}, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.globalNavigation__suitesReminder.globalNavigation__suitesReminder-bottomLeft { | ||
jared-dickman marked this conversation as resolved.
Show resolved
Hide resolved
|
||
left: calc(var(--nav-width) + var(--margin-xs)) !important; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import 'src/styles/_variables.css' | ||
import './suites-reminder.css' | ||
import { type ReactNode } from 'react' | ||
import { Button, notification, Space } from 'src/components' | ||
import { FontWeightStrong } from 'src/styles/style' | ||
|
||
export interface ISuitesReminderOptions { | ||
onClose: () => void | ||
onRemindMeLater: () => void | ||
onTakeMeThere: () => void | ||
duration?: number | ||
title?: string | ||
message?: string | ||
} | ||
|
||
type OpenNotificationFn = () => void | ||
type ContextHolder = ReactNode | ||
|
||
export type SuitesReminderHook = [OpenNotificationFn, ContextHolder] | ||
|
||
const DefaultReminderDuration = 4.5 as const // same as antd notification default duration | ||
const DefaultTitle = 'Join the new mParticle Experience!' as const | ||
const DefaultMessage = | ||
'Managing your data is easier than ever with the new mParticle experience. Try out the latest features with ease, and switch back to the classic experience anytime from the side navigation.' as const | ||
|
||
export const useSuitesReminder = (options: ISuitesReminderOptions): SuitesReminderHook => { | ||
const { | ||
onClose, | ||
onRemindMeLater, | ||
onTakeMeThere, | ||
duration = DefaultReminderDuration, | ||
title = DefaultTitle, | ||
message = DefaultMessage, | ||
} = options | ||
|
||
const [notificationApi, contextHolder] = notification.useNotification({ | ||
prefixCls: 'globalNavigation__suitesReminder', | ||
duration, | ||
placement: 'bottomLeft', | ||
}) | ||
|
||
const openNotification = (): void => { | ||
const key = `notification-${Date.now()}` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be a bit of a nit on my part, but I think using date conversion for a key might be overkill and might have a performance hit. Why not just create a simple increment function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting. Haven't given much thought to it but am always concerned with performance. I think in this case we will be fine since it will never be the case of showing more than just a few notifications at a time. Also it's the way Ant suggests in their docs. |
||
const btn = ( | ||
<Space> | ||
<Button | ||
type="link" | ||
size="small" | ||
onClick={_event => { | ||
onRemindMeLater() | ||
notificationApi.destroy(key) | ||
}}> | ||
Remind me later | ||
</Button> | ||
<Button | ||
type="primary" | ||
size="small" | ||
onClick={_event => { | ||
onTakeMeThere() | ||
notificationApi.destroy(key) | ||
}}> | ||
Take me there | ||
</Button> | ||
</Space> | ||
) | ||
|
||
notificationApi.open({ | ||
message: <span style={{ fontWeight: FontWeightStrong }}>{title}</span>, | ||
description: message, | ||
btn, | ||
key, | ||
onClose, | ||
}) | ||
} | ||
|
||
return [openNotification, contextHolder] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure that's the best way of mocking stuff in Storybook. We are still learning how to test in the Storybook context 😅