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
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
/** @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
<?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="M955.7 856l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zM480 416c0-4.4 3.6-8 8-8h48c4.4 0 8 3.6 8 8v184c0 4.4-3.6 8-8 8h-48c-4.4 0-8-3.6-8-8V416zm32 352a48.01 48.01 0 0 1 0-96 48.01 48.01 0 0 1 0 96z"/>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment