Skip to content

Instantly share code, notes, and snippets.

@grantglidewell
Last active March 6, 2020 17:18
Show Gist options
  • Save grantglidewell/b9624f6b5c35f6152e9c6c89bf672959 to your computer and use it in GitHub Desktop.
Save grantglidewell/b9624f6b5c35f6152e9c6c89bf672959 to your computer and use it in GitHub Desktop.
React Notification System (toaster)
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" standalone="no"?>
<svg fill="white" xmlns="http://www.w3.org/2000/svg" class="icon" viewBox="0 0 1024 1024">
<path d="M512 64C264.6 64 64 264.6 64 512s200.6 448 448 448 448-200.6 448-448S759.4 64 512 64zm32 664c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V456c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v272zm-32-344a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"/>
</svg>
/** @jsx jsx */
import { jsx, css } from '@emotion/core';
import PropTypes from 'prop-types';
import styles from './notification.styles';
import { useTimeout } from '../utils/hooks';
import info from './info.svg';
import success from './success.svg';
import warn from './warn.svg';
import error from './error.svg';
const messageTypes = {
warn,
error,
info,
success,
};
const Notification = ({
notification: { id, type, message },
removeNotification,
index,
delay,
}) => {
useTimeout(() => removeNotification(id), delay);
return (
<div
css={[
styles.notice,
styles[`${type}Notice`],
css`
top: ${index * 67}px;
`,
]}
>
<img src={messageTypes[type]} css={styles[type]} alt={type} />
<p css={styles.message}>{message}</p>
<button
type="button"
onClick={() => removeNotification(id)}
css={styles.close}
>
<span>close notification</span>
</button>
</div>
);
};
Notification.propTypes = {
notification: PropTypes.shape({
id: PropTypes.number.isRequired,
message: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
}).isRequired,
removeNotification: PropTypes.func.isRequired,
index: PropTypes.number.isRequired,
delay: PropTypes.number,
};
Notification.defaultProps = {
delay: 6000,
};
export default Notification;
import { css } from '@emotion/core';
export default {
notice: css`
position: absolute;
padding: 8px;
border-radius: 3px;
right: 5%;
margin-top: 10px;
background-color: #fff;
display: flex;
align-items: center;
`,
close: css`
color: #bbb8b8;
border: none;
background: none;
position: relative;
top: -12px;
right: -8px;
&:after {
content: '×';
font-size: 24px;
font-weight: 300;
line-height: 14px;
}
&:hover {
color: black;
}
span {
display: none;
}
`,
message: css`
margin: 0 10px;
`,
// type styles
warnNotice: css`
border: solid 1px orange;
`,
infoNotice: css`
border: solid 1px blue;
`,
errorNotice: css`
border: solid 1px red;
`,
successNotice: css`
border: solid 1px green;
`,
warn: css`
display: flex;
border-radius: 50%;
background-color: orange;
width: 25px;
padding: 3px;
padding-bottom: 5px;
height: 100%;
`,
info: css`
display: flex;
border-radius: 50%;
background-color: blue;
width: 25px;
padding: 5px;
height: 100%;
`,
error: css`
display: flex;
border-radius: 50%;
background-color: red;
width: 25px;
padding: 5px;
height: 100%;
`,
success: css`
display: flex;
border-radius: 50%;
background-color: green;
width: 25px;
padding: 5px;
height: 100%;
`,
};
import React, { createContext, useState, useContext } from 'react';
import PropTypes from 'prop-types';
import { Notification } from '../components';
const NotificationContext = createContext({});
const NotificationProvider = ({ children }) => {
const [notifications, updateNotifications] = useState([]);
/**
* add a notification
* @param {object} notification
* @param {'warn' | 'error' | 'notify' | 'success'} notification.type
* @param {string} notification.message - the message the user will see
* @param {number} notification.id - [generated on creation]
*/
const addNotification = notification => {
updateNotifications([
...notifications,
{
...notification,
id: Date.now(),
},
]);
};
const removeNotification = id => {
updateNotifications(notifications.filter(not => not.id !== id));
};
return (
<NotificationContext.Provider
value={{ notifications, addNotification, removeNotification }}
>
{children}
</NotificationContext.Provider>
);
};
NotificationProvider.propTypes = {
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node,
]).isRequired,
};
NotificationProvider.displayName = 'NotificationProvider';
const Notify = () => {
const { notifications, removeNotification } = useContext(NotificationContext);
return notifications.length
? notifications.map((note, i) => {
return (
<Notification
key={note.id}
index={i}
notification={note}
removeNotification={removeNotification}
/>
);
})
: null;
};
export { NotificationProvider, NotificationContext, Notify };
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment