Initial commit
This commit is contained in:
60
src/actions/config.js
Normal file
60
src/actions/config.js
Normal file
@ -0,0 +1,60 @@
|
||||
import yaml from 'js-yaml';
|
||||
|
||||
export const CONFIG = {
|
||||
REQUEST: 'REQUEST',
|
||||
SUCCESS: 'SUCCESS',
|
||||
FAILURE: 'FAILURE'
|
||||
};
|
||||
|
||||
export function configLoaded(config) {
|
||||
return {
|
||||
type: CONFIG.SUCCESS,
|
||||
payload: config
|
||||
};
|
||||
}
|
||||
|
||||
export function configLoading() {
|
||||
return {
|
||||
type: CONFIG.REQUEST
|
||||
};
|
||||
}
|
||||
|
||||
export function configFailed(err) {
|
||||
return {
|
||||
type: CONFIG.FAILURE,
|
||||
error: 'Error loading config',
|
||||
payload: err
|
||||
};
|
||||
}
|
||||
|
||||
export function loadConfig(config) {
|
||||
if (window.CMS_CONFIG) {
|
||||
return configLoaded(window.CMS_CONFIG);
|
||||
}
|
||||
return (dispatch, getState) => {
|
||||
dispatch(configLoading());
|
||||
|
||||
fetch('config.yml').then((response) => {
|
||||
if (response.status !== 200) {
|
||||
throw `Failed to load config.yml (${response.status})`;
|
||||
}
|
||||
|
||||
response.text().then(parseConfig).then((config) => dispatch(configLoaded(config)));
|
||||
}).catch((err) => {
|
||||
dispatch(configFailed(err));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function parseConfig(data) {
|
||||
const config = yaml.safeLoad(data);
|
||||
|
||||
if (typeof CMS_ENV === 'string' && config[CMS_ENV]) {
|
||||
for (var key in config[CMS_ENV]) {
|
||||
if (config[CMS_ENV].hasOwnProperty(key)) {
|
||||
config[key] = config[CMS_ENV][key];
|
||||
}
|
||||
}
|
||||
}
|
||||
return config;
|
||||
}
|
58
src/containers/App.js
Normal file
58
src/containers/App.js
Normal file
@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { loadConfig } from '../actions/config';
|
||||
|
||||
class App extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatch(loadConfig());
|
||||
}
|
||||
|
||||
configError(config) {
|
||||
return <div>
|
||||
<h1>Error loading the CMS configuration</h1>
|
||||
|
||||
<div>
|
||||
<p>The "config.yml" file could not be loaded or failed to parse properly.</p>
|
||||
<p><strong>Error message:</strong> {config.get('error')}</p>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
configLoading() {
|
||||
return <div>
|
||||
<h1>Loading configuration...</h1>
|
||||
</div>;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { config, children } = this.props;
|
||||
|
||||
if (config === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (config.get('error')) {
|
||||
return this.configError(config);
|
||||
}
|
||||
|
||||
if (config.get('isFetching')) {
|
||||
return this.configLoading();
|
||||
}
|
||||
|
||||
return (
|
||||
<div>{children}</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
config: state.config
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(App);
|
26
src/containers/DashboardPage.js
Normal file
26
src/containers/DashboardPage.js
Normal file
@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import { Link } from 'react-router';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
class DashboardPage extends React.Component {
|
||||
render() {
|
||||
const { collections } = this.props;
|
||||
|
||||
return <div>
|
||||
<h1>Dashboard</h1>
|
||||
{collections && collections.map((collection) => (
|
||||
<div key={collection.get('name')}>
|
||||
<Link to={`/collections/${collection.get('name')}`}>{collection.get('name')}</Link>
|
||||
</div>
|
||||
)).toArray()}
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
return {
|
||||
collections: state.collections
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(DashboardPage);
|
17
src/index.js
Normal file
17
src/index.js
Normal file
@ -0,0 +1,17 @@
|
||||
import React from 'react';
|
||||
import { render } from 'react-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import configureStore from './store/configureStore';
|
||||
import Routes from './routes/routes';
|
||||
import 'file?name=index.html!../example/index.html';
|
||||
|
||||
const store = configureStore();
|
||||
|
||||
const el = document.createElement('div');
|
||||
document.body.appendChild(el);
|
||||
|
||||
render((
|
||||
<Provider store={store}>
|
||||
<Routes/>
|
||||
</Provider>
|
||||
), el);
|
16
src/reducers/collections.js
Normal file
16
src/reducers/collections.js
Normal file
@ -0,0 +1,16 @@
|
||||
import Immutable from 'immutable';
|
||||
import { CONFIG } from '../actions/config';
|
||||
|
||||
export function collections(state = null, action) {
|
||||
switch (action.type) {
|
||||
case CONFIG.SUCCESS:
|
||||
const collections = action.payload && action.payload.collections;
|
||||
return Immutable.OrderedMap().withMutations((map) => {
|
||||
(collections || []).forEach(function(collection) {
|
||||
map.set(collection.name, Immutable.fromJS(collection));
|
||||
});
|
||||
});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
15
src/reducers/config.js
Normal file
15
src/reducers/config.js
Normal file
@ -0,0 +1,15 @@
|
||||
import Immutable from 'immutable';
|
||||
import { CONFIG } from '../actions/config';
|
||||
|
||||
export function config(state = null, action) {
|
||||
switch (action.type) {
|
||||
case CONFIG.REQUEST:
|
||||
return Immutable.Map({isFetching: true});
|
||||
case CONFIG.SUCCESS:
|
||||
return Immutable.fromJS(action.payload);
|
||||
case CONFIG.FAILURE:
|
||||
return Immutable.Map({error: action.payload.toString()});
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
12
src/routes/routes.js
Normal file
12
src/routes/routes.js
Normal file
@ -0,0 +1,12 @@
|
||||
import React from 'react';
|
||||
import { Router, Route, IndexRoute, browserHistory } from 'react-router';
|
||||
import App from '../containers/App';
|
||||
import DashboardPage from '../containers/DashboardPage';
|
||||
|
||||
export default () => (
|
||||
<Router history={browserHistory}>
|
||||
<Route path="/" component={App}>
|
||||
<IndexRoute component={DashboardPage}/>
|
||||
</Route>
|
||||
</Router>
|
||||
);
|
21
src/store/configureStore.js
Normal file
21
src/store/configureStore.js
Normal file
@ -0,0 +1,21 @@
|
||||
import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import { browserHistory } from 'react-router';
|
||||
import { syncHistory, routeReducer } from 'react-router-redux';
|
||||
import { config } from '../reducers/config';
|
||||
import { collections } from '../reducers/collections';
|
||||
|
||||
const reducer = combineReducers({
|
||||
config,
|
||||
collections,
|
||||
router: routeReducer
|
||||
});
|
||||
|
||||
const createStoreWithMiddleware = compose(
|
||||
applyMiddleware(thunkMiddleware, syncHistory(browserHistory)),
|
||||
window.devToolsExtension ? window.devToolsExtension() : (f) => f
|
||||
)(createStore);
|
||||
|
||||
export default (initialState) => (
|
||||
createStoreWithMiddleware(reducer, initialState)
|
||||
);
|
Reference in New Issue
Block a user