Skip to content

Commit

Permalink
feat: huge rewrite to separate admin and application and separate bun…
Browse files Browse the repository at this point in the history
…dles
  • Loading branch information
calvinl committed Mar 29, 2018
1 parent 819ab4f commit 0bdc1c4
Show file tree
Hide file tree
Showing 85 changed files with 554 additions and 175 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ defines the require() aliases used by both webpack and node.
Aliased paths are prefixed with one of two symbols, which denote different
things:

`@` - component and template paths, e.g. `@components`
`@` - aliased paths, e.g. `@admin, @app, @middleware`

`$` - server paths that are built by babel, e.g. `server/api`

Expand All @@ -94,7 +94,7 @@ in our components:
import SomeComponent from '../../../components/SomeComponent';
// This is way better
import SomeComponent from '@components/SomeComponent';
import SomeComponent from '@shared/components/SomeComponent';
```

You can add additional aliases in `package.json` to your own liking.
Expand Down
28 changes: 28 additions & 0 deletions client/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import './styles';
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import configureStore from '@admin/store';
import App from '@admin/containers/App';
import Loadable from 'react-loadable';

// Hydrate the redux store from server state.
const initialState = window.__INITIAL_STATE__;
const history = createHistory();
const store = configureStore(initialState, history);

// Render the application
window.main = () => {
Loadable.preloadReady().then(() => {
ReactDOM.hydrate(
<Provider store={store}>
<ConnectedRouter history={history}>
<App />
</ConnectedRouter>
</Provider>,
document.getElementById('app')
);
});
};
4 changes: 2 additions & 2 deletions client/index.js → client/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { ConnectedRouter } from 'react-router-redux';
import createHistory from 'history/createBrowserHistory';
import configureStore from '@store';
import App from '@containers/App';
import configureStore from '@app/store';
import App from '@app/containers/App';
import Loadable from 'react-loadable';

// Hydrate the redux store from server state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { NavLink, withRouter } from 'react-router-dom';
import { Header, Menu } from 'semantic-ui-react';
import { logout } from '@actions/auth';
import { logout } from '@app/actions/auth';

class HeaderView extends Component {
static propTypes = {
Expand Down
1 change: 1 addition & 0 deletions common/admin/components/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Header } from './Header';
22 changes: 22 additions & 0 deletions common/admin/containers/App/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { Switch } from 'react-router-dom';
import { Container } from 'semantic-ui-react';
import { RouteWithSubRoutes } from '@shared/components/common';
import { Header } from '@admin/components/common';
import { hot } from 'react-hot-loader';
import routes from '@admin/routes';

const App = () => {
return (
<Container fluid={true}>
<Header />
<Switch>
{routes.map(route => (
<RouteWithSubRoutes key={route.path} {...route} />
))}
</Switch>
</Container>
);
};

export default hot(module)(App);
File renamed without changes.
20 changes: 20 additions & 0 deletions common/admin/pages/Home/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import React, { Component } from 'react';
import { Helmet } from 'react-helmet';

class AdminHomePage extends Component {
render() {
return (
<div>
<Helmet>
<title>Admin</title>
</Helmet>
<h1>Admin Page</h1>
<p>
This is the admin home page. Work is still in progress.
</p>
</div>
);
}
}

export default AdminHomePage;
43 changes: 43 additions & 0 deletions common/admin/pages/Products/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { Helmet } from 'react-helmet';
import { searchProducts } from '@app/actions/search';
import { ProductSearch, ProductList } from '@app/components/products';

class AdminProductsPage extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
products: PropTypes.object.isRequired
};

componentDidMount() {
const { dispatch, products } = this.props;

if (!products.isLoaded) {
return dispatch(searchProducts({ query: ' ' }));
}
}

render() {
const { products, dispatch } = this.props;
const title = 'Products';

return (
<div>
<Helmet>
<title>{title}</title>
</Helmet>
<h1>{title}</h1>
<ProductSearch dispatch={dispatch} products={products} />
<ProductList products={products} />
</div>
);
}
}

const mapStateToProps = state => ({
products: state.search.products
});

export default connect(mapStateToProps)(AdminProductsPage);
File renamed without changes.
15 changes: 15 additions & 0 deletions common/admin/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';

import auth from '@app/reducers/auth';
import products from '@app/reducers/products';
import search from '@app/reducers/search';

const rootReducer = combineReducers({
routing: routerReducer,
auth,
products,
search
});

export default rootReducer;
9 changes: 9 additions & 0 deletions common/admin/routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import Error from '@admin/pages/Error';
import Home from '@admin/pages/Home';
import Products from '@admin/pages/Products';

export default [
{ path: '/admin', exact: true, component: Home },
{ path: '/admin/products', exact: true, component: Products },
{ path: '*', component: Error }
];
45 changes: 45 additions & 0 deletions common/admin/store/index.dev.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { compose, createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '@admin/reducers';
import { createLogger } from 'redux-logger';
import { callAPIMiddleware } from '@middleware';
import { routerMiddleware } from 'react-router-redux';

export default function configureStore(initialState, history = null) {
/* Middleware
* Configure this array with the middleware that you want included
*/
let middleware = [
thunk,
createLogger(),
callAPIMiddleware
];

if (history) {
middleware.push(routerMiddleware(history));
}

// Add universal enhancers here
let enhancers = [];

const composeEnhancers = (
typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
) || compose;
const enhancer = composeEnhancers(...[
applyMiddleware(...middleware),
...enhancers
]);

// create store with enhancers, middleware, reducers, and initialState
const store = createStore(rootReducer, initialState, enhancer);

if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
const nextRootReducer = require('../reducers').default;
store.replaceReducer(nextRootReducer);
});
}

return store;
}
File renamed without changes.
29 changes: 29 additions & 0 deletions common/admin/store/index.prod.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { compose, createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from '@admin/reducers';
import { callAPIMiddleware } from '@middleware';
import { routerMiddleware } from 'react-router-redux';

export default function configureStore(initialState, history = null) {
/* Middleware
* Configure this array with the middleware that you want included.
*/
let middleware = [ thunk, callAPIMiddleware ];

if (history) {
middleware.push(routerMiddleware(history));
}

// Add universal enhancers here
let enhancers = [];

const enhancer = compose(...[
applyMiddleware(...middleware),
...enhancers
]);

// create store with enhancers, middleware, reducers, and initialState
const store = createStore(rootReducer, initialState, enhancer);

return store;
}
2 changes: 1 addition & 1 deletion common/js/actions/auth.js → common/app/actions/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
SIGNUP_REQUEST, SIGNUP_SUCCESS, SIGNUP_FAILURE,
LOGIN_REQUEST, LOGIN_SUCCESS, LOGIN_FAILURE,
LOGOUT_REQUEST, LOGOUT_SUCCESS, LOGOUT_FAILURE
} from '@constants';
} from '@app/constants';

/**
* logout()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
LOAD_PRODUCTS_REQUEST,
LOAD_PRODUCTS_SUCCESS,
LOAD_PRODUCTS_FAILURE
} from '@constants';
} from '@app/constants';

export const loadProducts = (query = {}) => {
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
SEARCH_PRODUCTS_REQUEST,
SEARCH_PRODUCTS_SUCCESS,
SEARCH_PRODUCTS_FAILURE,
} from '@constants';
} from '@app/constants';
import { getEnv } from '@lib/env';
import AlgoliaSearch from '@lib/AlgoliaSearch';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { push } from 'react-router-redux';
import { Link } from 'react-router-dom';
import { Formik, Field } from 'formik';
import { Form } from 'semantic-ui-react';
import { Input, Button } from '@components/form';
import { login } from '@actions/auth';
import { Input, Button } from '@shared/components/form';
import { login } from '@app/actions/auth';
import transformErrors from '@lib/transformErrors';
import schema from './schema';
import css from './index.scss';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { push } from 'react-router-redux';
import { Link } from 'react-router-dom';
import { Formik, Field } from 'formik';
import { Form } from 'semantic-ui-react';
import { Input, Button } from '@components/form';
import { signup } from '@actions/auth';
import { Input, Button } from '@shared/components/form';
import { signup } from '@app/actions/auth';
import transformErrors from '@lib/transformErrors';
import userSchema from '@schemas/user';
import css from './index.scss';
Expand Down
File renamed without changes.
File renamed without changes.
59 changes: 59 additions & 0 deletions common/app/components/common/Header/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import React, { Fragment, Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { NavLink, withRouter } from 'react-router-dom';
import { Header, Menu } from 'semantic-ui-react';
import { logout } from '@app/actions/auth';

class HeaderView extends Component {
static propTypes = {
auth: PropTypes.object.isRequired,
dispatch: PropTypes.func.isRequired
}

logout = () => {
const { dispatch } = this.props;

dispatch(logout());
}

renderUser = () => {
const { auth } = this.props;

if (auth.isLoggedIn) {
return (
<Fragment>
<Menu.Item><b>{auth.user.username}</b></Menu.Item>
<Menu.Item as="a" content="Logout" onClick={this.logout} />
</Fragment>
);
}

return (
<Fragment>
<Menu.Item to="/login" as={NavLink} content="Login" />
<Menu.Item to="/signup" as={NavLink} content="Signup" />
</Fragment>
);
}

render() {
return (
<Header>
<Menu size="massive">
<Menu.Item to="/" exact as={NavLink} content="Home" />
<Menu.Item to="/products" exact as={NavLink} content="Products" />
<Menu.Menu position="right">
{this.renderUser()}
</Menu.Menu>
</Menu>
</Header>
);
}
}

const mapStateToProps = (state) => ({
auth: state.auth
});

export default withRouter(connect(mapStateToProps)(HeaderView));
2 changes: 2 additions & 0 deletions common/app/components/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as Footer } from './Footer';
export { default as Header } from './Header';
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Loader } from 'semantic-ui-react';
import { ProductCard } from '@components/products';
import { ProductCard } from '@app/components/products';
import classnames from 'classnames';
import css from './index.scss';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Input, Form } from 'semantic-ui-react';
import { searchProducts } from '@actions/search';
import { searchProducts } from '@app/actions/search';
import { debounce } from 'lodash';
import classnames from 'classnames';
import css from './index.scss';
Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 0bdc1c4

Please sign in to comment.