-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Wire notification to "add pattern" and "delete pattern" * Add test for notifications state * Add interaction stories for toast notifications * Linting * Swap nanoid out for crypto.randomUUID() in an attempt to avoid an out of memory error on the Cloud.gov Pages build container. * Remove superfluous ID prop
- Loading branch information
1 parent
beb29c8
commit 357ae72
Showing
15 changed files
with
413 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
39 changes: 39 additions & 0 deletions
39
packages/design/src/FormManager/common/Notifications/NotificationAlert.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { NotificationAlert } from './NotificationAlert'; | ||
|
||
export default { | ||
title: 'FormManager/Notifications/NotificationAlert', | ||
component: NotificationAlert, | ||
} satisfies Meta<typeof NotificationAlert>; | ||
|
||
export const Info: StoryObj<typeof NotificationAlert> = { | ||
args: { | ||
type: 'info', | ||
message: 'Informational message', | ||
}, | ||
}; | ||
export const Warning: StoryObj<typeof NotificationAlert> = { | ||
args: { | ||
type: 'warning', | ||
message: 'Informational message', | ||
}, | ||
}; | ||
export const Success: StoryObj<typeof NotificationAlert> = { | ||
args: { | ||
type: 'success', | ||
message: 'Success message', | ||
}, | ||
}; | ||
export const Error: StoryObj<typeof NotificationAlert> = { | ||
args: { | ||
type: 'error', | ||
message: 'Error message', | ||
}, | ||
}; | ||
export const Emergency: StoryObj<typeof NotificationAlert> = { | ||
args: { | ||
type: 'emergency', | ||
message: 'Emergency message', | ||
}, | ||
}; |
28 changes: 28 additions & 0 deletions
28
packages/design/src/FormManager/common/Notifications/NotificationAlert.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import classNames from 'classnames'; | ||
import React from 'react'; | ||
|
||
import { type Notification } from './store'; | ||
|
||
type NotificationAlertProps = { | ||
type: Notification['type']; | ||
message: Notification['message']; | ||
}; | ||
|
||
export const NotificationAlert = ({ | ||
type, | ||
message, | ||
}: NotificationAlertProps) => ( | ||
<div | ||
className={classNames( | ||
'usa-alert usa-alert--slim bg-light-blue padding-2', | ||
`usa-alert--${type}` | ||
)} | ||
role="alert" | ||
aria-live="assertive" | ||
aria-atomic="true" | ||
> | ||
<div className="usa-alert__body"> | ||
<p className="usa-alert__text">{message}</p> | ||
</div> | ||
</div> | ||
); |
40 changes: 40 additions & 0 deletions
40
packages/design/src/FormManager/common/Notifications/Notifications.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { Meta, StoryObj } from '@storybook/react'; | ||
import React from 'react'; | ||
|
||
import { Notifications } from './Notifications'; | ||
import { FormManagerProvider, useFormManagerStore } from '../../store'; | ||
import { | ||
createTestForm, | ||
createTestFormManagerContext, | ||
} from '../../../test-form'; | ||
|
||
const StoryImpl = () => { | ||
const { addNotification } = useFormManagerStore(); | ||
return ( | ||
<> | ||
<button | ||
onClick={() => addNotification('info', 'Notification triggered!')} | ||
> | ||
Trigger Notification | ||
</button> | ||
<Notifications /> | ||
</> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'FormManager/Notifications/Notifications', | ||
component: Notifications, | ||
decorators: [ | ||
() => ( | ||
<FormManagerProvider | ||
context={createTestFormManagerContext()} | ||
form={createTestForm()} | ||
> | ||
<StoryImpl /> | ||
</FormManagerProvider> | ||
), | ||
], | ||
} satisfies Meta<typeof Notifications>; | ||
|
||
export const Default: StoryObj<typeof Notifications> = {}; |
26 changes: 26 additions & 0 deletions
26
packages/design/src/FormManager/common/Notifications/Notifications.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import React from 'react'; | ||
import { useFormManagerStore } from '../../store'; | ||
import { NotificationAlert } from './NotificationAlert'; | ||
|
||
export const Notifications = () => { | ||
const { notifications } = useFormManagerStore(); | ||
return ( | ||
<div | ||
className={`position-fixed z-200`} | ||
style={{ | ||
top: '60px', | ||
left: '50%', | ||
transform: 'translateX(-50%)', | ||
maxWidth: '90%', | ||
}} | ||
> | ||
{notifications.map(notification => ( | ||
<NotificationAlert | ||
key={notification.id} | ||
type={notification.type} | ||
message={notification.message} | ||
/> | ||
))} | ||
</div> | ||
); | ||
}; |
2 changes: 2 additions & 0 deletions
2
packages/design/src/FormManager/common/Notifications/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { Notifications } from './Notifications'; | ||
export { type NotificationSlice, createNotificationsSlice } from './store'; |
25 changes: 25 additions & 0 deletions
25
packages/design/src/FormManager/common/Notifications/store.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { describe, expect, test } from 'vitest'; | ||
import { create } from 'zustand'; | ||
|
||
import { createNotificationsSlice } from './store'; | ||
|
||
const wait = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); | ||
|
||
describe('Notifications store', () => { | ||
test('should register notification', async () => { | ||
const timeoutMs = 1; | ||
const store = create(createNotificationsSlice(timeoutMs)); | ||
const state = store.getState(); | ||
state.addNotification('info', 'Pattern added.'); | ||
const notifications = store.getState().notifications; | ||
|
||
expect(notifications.length).toEqual(1); | ||
expect(typeof notifications[0].id).toEqual('string'); | ||
expect(notifications[0].message).toEqual('Pattern added.'); | ||
expect(notifications[0].type).toEqual('info'); | ||
|
||
// Wait for the timeout and confirm the notification has been removed. | ||
await wait(timeoutMs); | ||
expect(store.getState().notifications.length).toEqual(0); | ||
}); | ||
}); |
45 changes: 45 additions & 0 deletions
45
packages/design/src/FormManager/common/Notifications/store.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { StateCreator } from 'zustand'; | ||
|
||
type NotificationType = 'info' | 'warning' | 'success' | 'error' | 'emergency'; | ||
|
||
export type Notification = { | ||
type: NotificationType; | ||
id: string; | ||
message: string; | ||
}; | ||
|
||
export type NotificationSlice = { | ||
notifications: Notification[]; | ||
addNotification: (type: NotificationType, message: string) => void; | ||
}; | ||
|
||
type NotificationStoreCreator = StateCreator< | ||
NotificationSlice, | ||
[], | ||
[], | ||
NotificationSlice | ||
>; | ||
|
||
export const createNotificationsSlice = | ||
(timeout: number = 5000): NotificationStoreCreator => | ||
set => ({ | ||
notifications: [], | ||
addNotification: (type, message) => { | ||
const id = crypto.randomUUID(); | ||
set(state => ({ | ||
notifications: [...state.notifications, { id, type, message }], | ||
})); | ||
|
||
// Add an extra second timeout for each 120 words in the message. | ||
const naiveWordCount = message.split(' ').length; | ||
const extraTimeout = Math.floor(naiveWordCount / 120) * 1000; | ||
|
||
setTimeout(() => { | ||
set(state => ({ | ||
notifications: state.notifications.filter( | ||
notification => notification.id !== id | ||
), | ||
})); | ||
}, timeout + extraTimeout); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.