mirror of
https://github.com/vale981/Vulcan
synced 2025-03-06 01:51:40 -05:00
redux basic setup (to be improved) - test case on FlashMessages, used in PostNewForm
This commit is contained in:
parent
e88ecae84d
commit
f6bbbd14ca
14 changed files with 145 additions and 32 deletions
|
@ -6,6 +6,7 @@ aldeed:schema-deny@1.1.0
|
|||
aldeed:schema-index@1.1.0
|
||||
aldeed:simple-schema@1.5.3
|
||||
allow-deny@1.0.5
|
||||
apollo@0.1.2
|
||||
autoupdate@1.3.11
|
||||
babel-compiler@6.9.1
|
||||
babel-runtime@0.1.11
|
||||
|
|
|
@ -10,21 +10,21 @@ class Flash extends Component{
|
|||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.context.messages.markAsSeen(this.props.message._id);
|
||||
this.props.markAsSeen(this.props.message._id);
|
||||
}
|
||||
|
||||
dismissFlash(e) {
|
||||
e.preventDefault();
|
||||
this.context.messages.clear(this.props.message._id);
|
||||
this.props.clear(this.props.message._id);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
let type = this.props.message.type;
|
||||
type = type === "error" ? "danger" : type; // if type is "error", use "danger" instead
|
||||
let flashType = this.props.message.flashType;
|
||||
flashType = flashType === "error" ? "danger" : flashType; // if flashType is "error", use "danger" instead
|
||||
|
||||
return (
|
||||
<Alert className="flash-message" bsStyle={type} onDismiss={this.dismissFlash}>
|
||||
<Alert className="flash-message" bsStyle={flashType} onDismiss={this.dismissFlash}>
|
||||
{this.props.message.content}
|
||||
</Alert>
|
||||
)
|
||||
|
@ -35,8 +35,4 @@ Flash.propTypes = {
|
|||
message: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
Flash.contextTypes = {
|
||||
messages: React.PropTypes.object.isRequired
|
||||
}
|
||||
|
||||
module.exports = Flash;
|
|
@ -1,10 +1,12 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import React from 'react';
|
||||
|
||||
const FlashMessages = ({messages}) => {
|
||||
const FlashMessages = ({messages, clear, markAsSeen}) => {
|
||||
return (
|
||||
<div className="flash-messages">
|
||||
{messages.map((message, index) => <Telescope.components.Flash key={index} message={message} />)}
|
||||
{messages
|
||||
.filter(message => message.show)
|
||||
.map(message => <Telescope.components.Flash key={message._id} message={message} clear={clear} markAsSeen={markAsSeen} />)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ import { FlashContainer } from "meteor/nova:core";
|
|||
class Layout extends Component {
|
||||
|
||||
render() {
|
||||
|
||||
return (
|
||||
<div className="wrapper" id="wrapper">
|
||||
|
||||
|
@ -17,7 +16,7 @@ class Layout extends Component {
|
|||
|
||||
<div className="main">
|
||||
|
||||
<FlashContainer component={Telescope.components.FlashMessages}/>
|
||||
<FlashContainer {...this.props} component={Telescope.components.FlashMessages}/>
|
||||
|
||||
<Telescope.components.Newsletter />
|
||||
|
||||
|
@ -29,7 +28,6 @@ class Layout extends Component {
|
|||
|
||||
</div>
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
import React, { PropTypes, Component } from 'react';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
import { intlShape } from 'react-intl';
|
||||
import NovaForm from "meteor/nova:forms";
|
||||
import { withRouter } from 'react-router'
|
||||
|
@ -20,7 +22,7 @@ const PostsNewForm = (props, context) => {
|
|||
collection={Posts}
|
||||
methodName="posts.new"
|
||||
successCallback={(post)=>{
|
||||
context.messages.flash(context.intl.formatMessage({id: "posts.created_message"}), "success");
|
||||
props.flash(context.intl.formatMessage({id: "posts.created_message"}), "success");
|
||||
router.push({pathname: Posts.getPageUrl(post)});
|
||||
}}
|
||||
/>
|
||||
|
@ -31,11 +33,14 @@ const PostsNewForm = (props, context) => {
|
|||
|
||||
PostsNewForm.contextTypes = {
|
||||
currentUser: React.PropTypes.object,
|
||||
messages: React.PropTypes.object,
|
||||
intl: intlShape
|
||||
};
|
||||
|
||||
PostsNewForm.displayName = "PostsNewForm";
|
||||
|
||||
module.exports = withRouter(PostsNewForm);
|
||||
export default withRouter(PostsNewForm);
|
||||
const mapStateToProps = state => ({ messages: state.messages });
|
||||
const mapDispatchToProps = dispatch => bindActionCreators(Telescope.actions.messages, dispatch);
|
||||
|
||||
// note: why having both module.exports & export default?
|
||||
module.exports = withRouter(connect(mapStateToProps, mapDispatchToProps)(PostsNewForm));
|
||||
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(PostsNewForm));
|
|
@ -12,6 +12,10 @@ import Helmet from 'react-helmet';
|
|||
import Cookie from 'react-cookie';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
// redux
|
||||
import { Provider } from 'react-redux';
|
||||
import store from "./store.js";
|
||||
|
||||
Telescope.routes.indexRoute = { name: "posts.list", component: Telescope.components.PostsHome };
|
||||
|
||||
Meteor.startup(() => {
|
||||
|
@ -24,13 +28,19 @@ Meteor.startup(() => {
|
|||
{name:"users.edit", path:"users/:slug/edit", component:Telescope.components.UsersAccount},
|
||||
{name:"app.notfound", path:"*", component:Telescope.components.Error404},
|
||||
]);
|
||||
|
||||
const ProvidedApp = (props) => (
|
||||
<Provider store={store}>
|
||||
<Telescope.components.App {...props} />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const AppRoutes = {
|
||||
path: '/',
|
||||
component: Telescope.components.App,
|
||||
component: ProvidedApp,
|
||||
indexRoute: Telescope.routes.indexRoute,
|
||||
childRoutes: Telescope.routes.routes
|
||||
}
|
||||
};
|
||||
|
||||
let history;
|
||||
|
||||
|
|
16
packages/nova-base-routes/lib/store.js
Normal file
16
packages/nova-base-routes/lib/store.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { createStore, compose, combineReducers, } from 'redux';
|
||||
import Telescope from 'meteor/nova:lib';
|
||||
|
||||
const rootReducer = combineReducers(Telescope.reducers);
|
||||
|
||||
const defaultState = {
|
||||
messages: [],
|
||||
};
|
||||
|
||||
const enhancers = compose(
|
||||
typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : f => f
|
||||
);
|
||||
|
||||
const store = createStore(rootReducer, defaultState);
|
||||
|
||||
export default store;
|
|
@ -24,6 +24,7 @@ Package.onUse(function (api) {
|
|||
]);
|
||||
|
||||
api.addFiles([
|
||||
'lib/store.js',
|
||||
'lib/routes.jsx'
|
||||
], ['client', 'server']);
|
||||
|
||||
|
|
|
@ -3,8 +3,8 @@ import './modules.js';
|
|||
import Messages from './messages.js';
|
||||
import ModalTrigger from './components/ModalTrigger.jsx';
|
||||
import ContextPasser from './components/ContextPasser.jsx';
|
||||
import FlashContainer from './containers/FlashContainer.jsx';
|
||||
import FlashContainer from "./containers/FlashContainer.jsx";
|
||||
import AppComposer from './containers/AppComposer.jsx';
|
||||
// import NovaCounts from './counts.js';
|
||||
|
||||
export { Messages, ModalTrigger, ContextPasser, AppComposer, FlashContainer};
|
||||
export { Messages, ModalTrigger, ContextPasser, AppComposer, FlashContainer };
|
|
@ -1,15 +1,64 @@
|
|||
import React from 'react';
|
||||
import Messages from "../messages.js";
|
||||
import Telescope from 'meteor/nova:lib';
|
||||
//import { messagesActions } from "../messages.js";
|
||||
|
||||
import { createContainer } from 'meteor/react-meteor-data';
|
||||
// import { createContainer } from 'meteor/react-meteor-data';
|
||||
|
||||
const FlashContainer = createContainer(() => {
|
||||
return {
|
||||
messages: Messages.collection.find({show: true}).fetch()
|
||||
// const FlashContainer = createContainer(() => {
|
||||
// return {
|
||||
// messages: Messages.collection.find({show: true}).fetch()
|
||||
// }
|
||||
// }, params => <params.component {...params} />);
|
||||
|
||||
// FlashContainer.displayName = "FlashContainer";
|
||||
|
||||
// module.exports = FlashContainer;
|
||||
// export default FlashContainer;
|
||||
|
||||
// note: messy redux test
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
// should go elsewhere...
|
||||
Telescope.reducers.messages = (state = [], action) => {
|
||||
let currentMsg = {};
|
||||
switch(action.type) {
|
||||
case 'FLASH':
|
||||
action.flashType = typeof action.flashType === 'undefined' ? 'error' : action.flashType;
|
||||
|
||||
return [
|
||||
...state,
|
||||
{ _id: state.length, content: action.content, flashType: action.flashType, seen: false, show: true },
|
||||
];
|
||||
case 'MARK_AS_SEEN':
|
||||
currentMsg = state[action.i];
|
||||
|
||||
return [
|
||||
...state.slice(0, action.i),
|
||||
{ ...currentMsg, seen: true },
|
||||
...state.slice(action.i + 1),
|
||||
];
|
||||
case 'CLEAR':
|
||||
currentMsg = state[action.i];
|
||||
|
||||
return [
|
||||
...state.slice(0, action.i),
|
||||
{ ...currentMsg, show: false },
|
||||
...state.slice(action.i + 1),
|
||||
];
|
||||
case 'CLEAR_SEEN':
|
||||
return state.map(message => ({ ...message, show: false }));
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}, params => <params.component {...params} />);
|
||||
};
|
||||
|
||||
FlashContainer.displayName = "FlashContainer";
|
||||
const mapStateToProps = state => ({
|
||||
messages: state.messages,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch => bindActionCreators(Telescope.actions.messages, dispatch);
|
||||
|
||||
const FlashContainer = connect(mapStateToProps, mapDispatchToProps)((props, context) => <props.component {...props} />);
|
||||
|
||||
module.exports = FlashContainer;
|
||||
export default FlashContainer;
|
|
@ -1,3 +1,5 @@
|
|||
import Telescope from 'meteor/nova:lib';
|
||||
|
||||
const Messages = {
|
||||
// Local (client-only) collection
|
||||
collection: new Meteor.Collection(null),
|
||||
|
@ -21,4 +23,32 @@ const Messages = {
|
|||
}
|
||||
};
|
||||
|
||||
// actions
|
||||
Telescope.actions.messages = {
|
||||
flash(content, flashType) {
|
||||
return {
|
||||
type: 'FLASH',
|
||||
content,
|
||||
flashType,
|
||||
};
|
||||
},
|
||||
clear(i) {
|
||||
return {
|
||||
type: 'CLEAR',
|
||||
i,
|
||||
};
|
||||
},
|
||||
markAsSeen(i) {
|
||||
return {
|
||||
type: 'MARK_AS_SEEN',
|
||||
i,
|
||||
};
|
||||
},
|
||||
clearSeen() {
|
||||
return {
|
||||
type: 'CLEAR_SEEN'
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
export default Messages;
|
|
@ -1,2 +1,3 @@
|
|||
import './callbacks.js';
|
||||
import './icons.js';
|
||||
import './icons.js';
|
||||
import './messages.js'; // import redux actions
|
|
@ -8,4 +8,4 @@ import ContextPasser from "./components/ContextPasser.jsx";
|
|||
import FlashContainer from "./containers/FlashContainer.jsx";
|
||||
import AppComposer from "./containers/AppComposer.jsx";
|
||||
|
||||
export { Messages, ModalTrigger, ContextPasser, AppComposer, FlashContainer};
|
||||
export { Messages, ModalTrigger, ContextPasser, AppComposer, FlashContainer };
|
|
@ -106,4 +106,8 @@ Telescope.statuses = [
|
|||
}
|
||||
];
|
||||
|
||||
// ---------------------------------- Redux ------------------------------------ //
|
||||
Telescope.actions = {};
|
||||
Telescope.reducers = {};
|
||||
|
||||
export default Telescope;
|
Loading…
Add table
Reference in a new issue