@@ -19,3 +32,8 @@ export default function Flash() {
Flash.displayName = 'Flash';
Flash.propTypes = propTypes;
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(Flash);
diff --git a/common/app/Flash/redux/index.js b/common/app/Flash/redux/index.js
index 8b13789179..e79dd0fd8c 100644
--- a/common/app/Flash/redux/index.js
+++ b/common/app/Flash/redux/index.js
@@ -1 +1,54 @@
+import { composeReducers } from 'berkeleys-redux-utils';
+import _ from 'lodash/fp';
+import ns from '../ns.json';
+
+export const alertTypes = _.keyBy(_.identity)([
+ 'success',
+ 'info',
+ 'warning',
+ 'danger'
+]);
+
+export const getFlashAction = _.flow(
+ _.property('meta'),
+ _.property('flash')
+);
+
+export const isFlashAction = _.flow(
+ getFlashAction,
+ Boolean
+);
+
+const defaultState = {
+ stack: [{ alertType: 'danger', message: 'foo bar' }]
+};
+
+const getNS = _.property(ns);
+
+export const latestMessageSelector = _.flow(
+ getNS,
+ _.property('stack'),
+ _.head,
+ _.defaultTo(_.stubObject)
+);
+
+export default composeReducers(
+ ns,
+ function metaReducer(state = defaultState, action) {
+ if (isFlashAction(action)) {
+ const { payload: { alertType, message } } = getFlashAction(action);
+ return {
+ ...state,
+ stack: [
+ ...state.stack,
+ {
+ alertType: alertTypes[alertType] || 'info',
+ message: _.escape(message)
+ }
+ ]
+ };
+ }
+ return state;
+ }
+);
diff --git a/common/app/reducer.js b/common/app/reducer.js
index e8915b6e91..7c5d882ce7 100644
--- a/common/app/reducer.js
+++ b/common/app/reducer.js
@@ -8,6 +8,7 @@ import nav from './Nav/redux';
import routes from './routes/redux';
import toasts from './Toasts/redux';
import files from './files';
+import flash from './Flash/redux';
// not ideal but should go away once we move to react-redux-form
import { projectNormalizer } from './routes/Challenges/redux';
@@ -22,5 +23,6 @@ export default combineReducers(
routes,
toasts,
files,
+ flash,
_formReducer
);