Skip to content

Instantly share code, notes, and snippets.

@markerikson
Created January 21, 2018 15:43
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save markerikson/7621fca0e9704e99db5598bed0db861d to your computer and use it in GitHub Desktop.
Save markerikson/7621fca0e9704e99db5598bed0db861d to your computer and use it in GitHub Desktop.
React / Redux / Semantic-UI toast notifications implementation
import _ from "lodash";
import {generateUUID} from "common/utils/UUID";
import {
NOTIFICATION_CLEAR,
NOTIFICATION_DISMISS,
NOTIFICATION_SHOW,
NotificationType,
} from "./notificationConstants";
export {NotificationType};
export function showNotification(options = {}) {
return (dispatch, getState) => {
const {message = ""} = options;
const {header = ""} = options;
const {type = NotificationType.INFO} = options;
const {id = generateUUID("notification")} = options;
const {dismissAfter = 5000} = options;
const showPayload = {message, header, type, id};
dispatch({type : NOTIFICATION_SHOW, payload : showPayload});
if(_.isNumber(dismissAfter)) {
setTimeout(() => {
dispatch(dismissNotification(id));
}, dismissAfter);
}
}
}
export function dismissNotification(id) {
return {
type : NOTIFICATION_DISMISS,
payload : {id}
};
}
export function clearAllNotifications() {
return {
type : NOTIFICATION_CLEAR,
};
}
export const NOTIFICATION_SHOW = "NOTIFICATION_SHOW";
export const NOTIFICATION_DISMISS = "NOTIFICATION_DISMISS";
export const NOTIFICATION_CLEAR = "NOTIFICATION_CLEAR";
export const NotificationType = {
SUCCESS : "SUCCESS",
INFO : "INFO",
WARNING : "WARNING",
ERROR : "ERROR",
}
import React, {Component} from "react";
import {connect} from "react-redux";
import _ from "lodash";
import { Message } from "semantic-ui-react";
import {Portal} from 'react-portal';
import {selectNotifications} from "./notificationSelectors";
import {dismissNotification} from "./notificationActions";
const mapState = (state) => ({
notifications : selectNotifications(state),
});
const NOTIFICATION_CONTAINER_STYLE = {
position : "fixed",
top : "10px",
right : 0,
left : 0,
zIndex : 1000,
width : "80%",
maxWidth : "400px",
margin : "auto",
};
const Notification = ({message, header, type, id, onCloseClick=_.noop}) => {
let headerText = header;
let messageText = message;
if(!headerText) {
headerText = message;
messageText = null;
}
const messageHeader = headerText ? <Message.Header>{headerText}</Message.Header> : null;
// Turn the type string into a boolean prop with the same name
const typeProp = type.toLowerCase();
const typeObj = { [typeProp] : true};
if(messageText) {
const messagePieces = messageText.split("\n");
messageText = messagePieces.map(piece => <div>{piece}</div>);
}
const onDismiss = () => onCloseClick(id);
return (
<Message {...typeObj} onDismiss={onDismiss} >
{messageHeader}
<Message.Content>{messageText}</Message.Content>
</Message>
);
}
const actions = {dismissNotification};
export class NotificationManager extends Component {
render() {
let {notifications = []} = this.props;
const renderedNotifications = notifications.map( notification => {
const {id} = notification;
return (
<Notification
key={id}
onCloseClick={this.props.dismissNotification}
{...notification}
/>
)
});
return (
<Portal isOpened={true} key="notificationsPortal">
<div style={NOTIFICATION_CONTAINER_STYLE}>
{renderedNotifications}
</div>
</Portal>
)
}
}
export default connect(mapState, actions)(NotificationManager);
import {createReducer} from "common/utils/utils";
import {
NOTIFICATION_CLEAR,
NOTIFICATION_DISMISS,
NOTIFICATION_SHOW,
} from "./notificationConstants";
const initialState = [];
function filterNotifications(notifications, id) {
return notifications.filter(notification => notification.id !== id);
}
export function showNotification(state, payload) {
const filteredNotifications = filterNotifications(state, payload.id);
return [payload, ...filteredNotifications];
}
export function dismissNotification(state, payload) {
return filterNotifications(state, payload.id);
}
export function clearNotifications(state, payload) {
return [];
}
export default createReducer(initialState, {
[NOTIFICATION_CLEAR] : clearNotifications,
[NOTIFICATION_DISMISS] : dismissNotification,
[NOTIFICATION_SHOW] : showNotification,
});
import {createSelector} from "reselect";
export const selectUI = state => state.ui;
export const selectNotifications = createSelector(
selectUI,
ui => ui.notifications,
);
@c0rv4x
Copy link

c0rv4x commented Mar 20, 2018

Thanks for the nice and clean code!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment