Skip to content

Commit

Permalink
feat(notification): add options to pass a title & cta
Browse files Browse the repository at this point in the history
  • Loading branch information
dannyiacono committed Mar 20, 2020
1 parent ed8e327 commit 8c53d9d
Show file tree
Hide file tree
Showing 7 changed files with 240 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import { storiesOf } from '@storybook/react';
import { action } from '@storybook/addon-actions';
import { button, text, number, boolean, select } from '@storybook/addon-knobs';

import Button from '../Button';
Expand Down Expand Up @@ -86,6 +87,25 @@ storiesOf('Components|Notification', module)
>
show notification with the same id
</Button>
<Button
style={{ marginLeft: 20 }}
buttonType="positive"
onClick={() =>
Notification.success(
`${text('text', 'Hello world')} ${getUniqueNumber()}`,
{
duration: number('duration', 6000),
title: text('title', 'Example title'),
cta: {
label: text('cta.label', 'Example label'),
textLinkProps: { onClick: action('onClick') },
},
},
)
}
>
show notification with title and CTA
</Button>
</div>
);
},
Expand All @@ -97,9 +117,11 @@ storiesOf('Components|Notification', module)
<div>
<NotificationItem
hasCloseButton={boolean('hasCloseButton', true)}
title={text('title', 'Notification title')}
intent={select('intent', ['success', 'error', 'warning'], 'success')}
cta={{ label: text('cta.label', 'Notification CTA') }}
>
{text('text', 'Text for the notification')}
{text('body', 'Body for the notification')}
</NotificationItem>
</div>
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
cursor: default;
font-family: var(--font-stack-primary);
font-size: var(--font-size-m);
font-weight: var(--font-weight-medium);
line-height: var(--line-height-default);
}

Expand Down Expand Up @@ -46,10 +45,15 @@
margin-right: var(--spacing-s);
}

.NotificationItem__title {
font-weight: var(--font-weight-medium);
}

.NotificationItem__dismiss {
background: transparent;
border: none;
cursor: pointer;
outline: none;
pointer-events: all;
align-self: flex-start;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@ it('renders the component', () => {
expect(output).toMatchSnapshot();
});

it('renders the component with a title and a body', () => {
const output = shallow(
<NotificationItem title="Notification title" intent="success">
This is the body text.
</NotificationItem>,
);
expect(output).toMatchSnapshot();
});

it('renders the component with a cta', () => {
const output = shallow(
<NotificationItem
cta={{ label: 'This is some label text' }}
intent="warning"
>
This is the body text.
</NotificationItem>,
);
expect(output).toMatchSnapshot();
});

it('renders the component with "error" intent', () => {
const output = shallow(
<NotificationItem onClose={() => {}} intent="error">
Expand All @@ -21,7 +42,7 @@ it('renders the component with "error" intent', () => {
);

expect(output).toMatchSnapshot();
})
});

it('renders the component with "warning" intent', () => {
const output = shallow(
Expand All @@ -31,8 +52,7 @@ it('renders the component with "warning" intent', () => {
);

expect(output).toMatchSnapshot();
})

});

it(`has no a11y issues`, async () => {
const output = mount(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,25 @@ import React, { Component } from 'react';
import classNames from 'classnames';
import IconButton from '../IconButton';
import Icon from '../Icon';
import TextLink, { TextLinkProps } from '../TextLink';

import styles from './NotificationItem.css';

export type NotificationIntent = 'success' | 'error' | 'warning';

export interface NotificationCtaProps {
label: string;
textLinkProps: Partial<TextLinkProps>;
}

export interface NotificationItemProps {
intent: NotificationIntent;
hasCloseButton?: boolean;
onClose?: Function;
testId?: string;
children: React.ReactNode;
title?: string;
cta?: Partial<NotificationCtaProps>;
}

const defaultProps = {
Expand All @@ -26,8 +34,37 @@ export class NotificationItem extends Component<
> {
static defaultProps = defaultProps;

renderTitle() {
const { title, children } = this.props;

return (
<div className={styles.NotificationItem__title}>
{title ? title : children}
</div>
);
}

renderBody() {
const { title, children } = this.props;

return <div>{title && children}</div>;
}

renderCta() {
const { cta } = this.props;

if (cta && cta.label)
return (
<div>
<TextLink {...cta.textLinkProps} linkType="white">
{cta.label}
</TextLink>
</div>
);
}

render() {
const { children, testId, intent, onClose, hasCloseButton } = this.props;
const { testId, intent, onClose, hasCloseButton } = this.props;

const classes = classNames(styles.NotificationItem, {
[styles[`NotificationItem--${intent}`]]: true,
Expand All @@ -47,7 +84,11 @@ export class NotificationItem extends Component<
color="white"
/>
</div>
<div className={styles.NotificationItem__text}>{children}</div>
<div className={styles.NotificationItem__text}>
{this.renderTitle()}
{this.renderBody()}
{this.renderCta()}
</div>
{hasCloseButton && (
<IconButton
buttonType="white"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { PureComponent } from 'react';
import classNames from 'classnames';
import { NotificationIntent } from './NotificationItem';
import { NotificationIntent, NotificationCtaProps } from './NotificationItem';
import NotificationItemContainer from './NotificationItemContainer';

import styles from './NotificationsManager.css';
Expand All @@ -22,6 +22,8 @@ export interface Notification {
canClose: boolean;
isShown: boolean;
intent: NotificationIntent;
title?: string;
cta?: Partial<NotificationCtaProps>;
}

export type ShowAction<T> = (
Expand All @@ -31,6 +33,8 @@ export type ShowAction<T> = (
id?: string;
duration?: number;
canClose?: boolean;
title?: string;
cta?: Partial<NotificationCtaProps>;
},
) => T;

Expand Down Expand Up @@ -141,6 +145,8 @@ export class NotificationsManager extends PureComponent<
canClose,
isShown: true,
intent,
title: settings && settings.title,
cta: settings && settings.cta,
};

const alreadyThere = this.state.items.find(
Expand Down Expand Up @@ -185,6 +191,8 @@ export class NotificationsManager extends PureComponent<
hasCloseButton={item.canClose}
onClose={item.close}
isShown={item.isShown}
title={item.title}
cta={item.cta}
>
{item.text}
</NotificationItemContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ exports[`renders the component 1`] = `
<div
className="NotificationItem__text"
>
Notification text
<div
className="NotificationItem__title"
>
Notification text
</div>
<div />
</div>
<IconButton
buttonType="white"
Expand Down Expand Up @@ -73,7 +78,12 @@ exports[`renders the component with "error" intent 1`] = `
<div
className="NotificationItem__text"
>
Notification text
<div
className="NotificationItem__title"
>
Notification text
</div>
<div />
</div>
<IconButton
buttonType="white"
Expand Down Expand Up @@ -119,7 +129,126 @@ exports[`renders the component with "warning" intent 1`] = `
<div
className="NotificationItem__text"
>
Notification text
<div
className="NotificationItem__title"
>
Notification text
</div>
<div />
</div>
<IconButton
buttonType="white"
className="NotificationItem__dismiss"
disabled={false}
iconProps={
Object {
"icon": "Close",
}
}
label="Dismiss"
onClick={[Function]}
testId="cf-ui-notification-close"
withDropdown={false}
/>
</div>
`;

exports[`renders the component with a cta 1`] = `
<div
aria-live="assertive"
className="NotificationItem NotificationItem--warning"
data-intent="warning"
data-test-id="cf-ui-notification"
role="alert"
>
<div
className="NotificationItem__intent"
>
warning
</div>
<div
aria-hidden="true"
className="NotificationItem__icon"
>
<Icon
color="white"
icon="Warning"
size="small"
testId="cf-ui-icon"
/>
</div>
<div
className="NotificationItem__text"
>
<div
className="NotificationItem__title"
>
This is the body text.
</div>
<div />
<div>
<TextLink
disabled={false}
iconPosition="left"
linkType="white"
testId="cf-ui-text-link"
>
This is some label text
</TextLink>
</div>
</div>
<IconButton
buttonType="white"
className="NotificationItem__dismiss"
disabled={false}
iconProps={
Object {
"icon": "Close",
}
}
label="Dismiss"
onClick={[Function]}
testId="cf-ui-notification-close"
withDropdown={false}
/>
</div>
`;

exports[`renders the component with a title and a body 1`] = `
<div
aria-live="polite"
className="NotificationItem NotificationItem--success"
data-intent="success"
data-test-id="cf-ui-notification"
role="alert"
>
<div
className="NotificationItem__intent"
>
success
</div>
<div
aria-hidden="true"
className="NotificationItem__icon"
>
<Icon
color="white"
icon="CheckCircle"
size="small"
testId="cf-ui-icon"
/>
</div>
<div
className="NotificationItem__text"
>
<div
className="NotificationItem__title"
>
Notification title
</div>
<div>
This is the body text.
</div>
</div>
<IconButton
buttonType="white"
Expand Down
Loading

0 comments on commit 8c53d9d

Please sign in to comment.