Skip to content

Commit

Permalink
Add toast notifications capability (#469)
Browse files Browse the repository at this point in the history
Add toast notifications capability
  • Loading branch information
jeff-phillips-18 authored and cdcabrera committed Jan 22, 2018
1 parent 4e4f24b commit 94a354c
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 2 deletions.
4 changes: 3 additions & 1 deletion client/src/components/app.js
Expand Up @@ -8,6 +8,7 @@ import { routes } from '../routes';
import Store from '../redux/store';
import Content from './content/content';
import Masthead from './masthead/masthead';
import ToastNotificationsList from './toastNotificationList/toastNotificatinsList';
import VerticalNavigation from './verticalNavigation/verticalNavigation';

import logo from '../logo.svg';
Expand Down Expand Up @@ -39,7 +40,8 @@ class App extends React.Component {
<AboutModal.Versions>
<AboutModal.VersionItem label="Label" versionText="Version" />
</AboutModal.Versions>
</AboutModal>
</AboutModal>,
<ToastNotificationsList key="toastList" />
];
}
}
Expand Down
@@ -0,0 +1,81 @@
import { connect } from 'react-redux';
import React from 'react';
import PropTypes from 'prop-types';

import {
ToastNotificationList,
TimedToastNotification
} from 'patternfly-react';

import { bindMethods } from '../../common/helpers';
import Store from '../../redux/store';
import { toastNotificationTypes } from '../../redux/constants';

class ToastNotificationsList extends React.Component {
constructor() {
super();

bindMethods(this, ['onHover', 'onLeave', 'onDismiss']);
}

onHover() {
Store.dispatch({ type: toastNotificationTypes.TOAST_PAUSE });
}

onLeave() {
Store.dispatch({ type: toastNotificationTypes.TOAST_RESUME });
}

onDismiss(toast) {
Store.dispatch({
type: toastNotificationTypes.TOAST_REMOVE,
toast: toast
});
}

render() {
const { toasts, paused } = this.props;

return (
<ToastNotificationList>
{toasts &&
toasts.map((toast, index) => {
if (!toast.removed) {
return (
<TimedToastNotification
key={index}
toastIndex={index}
type={toast.alertType}
paused={paused}
onDismiss={e => this.onDismiss(toast)}
onMouseEnter={this.onHover}
onMouseLeave={this.onLeave}
>
<span>
<strong>{toast.header}</strong> &nbsp;
{toast.message}
</span>
</TimedToastNotification>
);
} else {
return null;
}
})}
</ToastNotificationList>
);
}
}

ToastNotificationsList.propTypes = {
toasts: PropTypes.array,
paused: PropTypes.bool
};

function mapStateToProps(state, ownProps) {
return {
toasts: state.toastNotifications.toasts,
paused: state.toastNotifications.paused
};
}

export default connect(mapStateToProps)(ToastNotificationsList);
3 changes: 3 additions & 0 deletions client/src/redux/constants/index.js
Expand Up @@ -5,6 +5,7 @@ import * as navigationBarTypes from './navigationBarConstants';
import * as reportsTypes from './reportsConstants';
import * as scansTypes from './scansConstants';
import * as sourcesTypes from './sourcesConstants';
import * as toastNotificationTypes from './toasNotificationConstants';
import * as viewToolbarTypes from './viewToolbarConstants';

const reduxTypes = {
Expand All @@ -15,6 +16,7 @@ const reduxTypes = {
reports: reportsTypes,
scans: scansTypes,
sources: sourcesTypes,
toastNotifications: toastNotificationTypes,
viewToolbar: viewToolbarTypes
};

Expand All @@ -27,6 +29,7 @@ export {
reportsTypes,
scansTypes,
sourcesTypes,
toastNotificationTypes,
viewToolbarTypes
};

Expand Down
6 changes: 6 additions & 0 deletions client/src/redux/constants/toasNotificationConstants.js
@@ -0,0 +1,6 @@
const TOAST_ADD = 'TOAST_ADD';
const TOAST_REMOVE = 'TOAST_REMOVE';
const TOAST_PAUSE = 'TOAST_PAUSE';
const TOAST_RESUME = 'TOAST_RESUME';

export { TOAST_ADD, TOAST_REMOVE, TOAST_PAUSE, TOAST_RESUME };
4 changes: 3 additions & 1 deletion client/src/redux/reducers/index.js
Expand Up @@ -9,6 +9,7 @@ import sourcesReducer from './sourcesReducer';
import sourcesToolbarReducer from './sourcesToolbarReducer';
import scansReducer from './scansReducer';
import scansToolbarReducer from './scansToolbarReducer';
import toastNotificationsReducer from './toastNotificationsReducer';

const reducers = {
about: aboutReducer,
Expand All @@ -19,7 +20,8 @@ const reducers = {
sources: sourcesReducer,
sourcesToolbar: sourcesToolbarReducer,
scans: scansReducer,
scansToolbar: scansToolbarReducer
scansToolbar: scansToolbarReducer,
toastNotifications: toastNotificationsReducer
};

const reduxReducers = combineReducers(reducers);
Expand Down
54 changes: 54 additions & 0 deletions client/src/redux/reducers/toastNotificationsReducer.js
@@ -0,0 +1,54 @@
import { toastNotificationTypes } from '../constants';

const initialState = {
toasts: [],
paused: false
};

export default function toastNotificationsReducer(
state = initialState,
action
) {
switch (action.type) {
case toastNotificationTypes.TOAST_ADD:
let newToast = {
header: action.header,
message: action.message,
alertType: action.alertType,
persistent: action.persistent
};
return Object.assign({}, state, {
toasts: [...state.toasts, newToast],
displayedToasts: state.displayedToasts + 1
});

case toastNotificationTypes.TOAST_REMOVE:
let index = state.toasts.indexOf(action.toast);
action.toast.removed = true;

let displayedToast = state.toasts.find(toast => {
return !toast.removed;
});

if (!displayedToast) {
return Object.assign({}, state, { toasts: [] });
}

return Object.assign({}, state, {
toasts: [
...state.toasts.slice(0, index),
action.toast,
...state.toasts.slice(index + 1)
]
});

case toastNotificationTypes.TOAST_PAUSE:
return Object.assign({}, state, { paused: true });

case toastNotificationTypes.TOAST_RESUME:
return Object.assign({}, state, { paused: false });

default:
return state;
}
}

0 comments on commit 94a354c

Please sign in to comment.