diff --git a/src/common/rootReducer.js b/src/common/rootReducer.js
index fc71e73..ddc73c2 100644
--- a/src/common/rootReducer.js
+++ b/src/common/rootReducer.js
@@ -2,6 +2,7 @@ import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import homeReducer from '../features/home/redux/reducer';
import commonReducer from '../features/common/redux/reducer';
+import userAdminReducer from '../features/user-admin/redux/reducer';
// NOTE 1: DO NOT CHANGE the 'reducerMap' name and the declaration pattern.
// This is used for Rekit cmds to register new features, remove features, etc.
@@ -12,6 +13,7 @@ const reducerMap = {
router: routerReducer,
home: homeReducer,
common: commonReducer,
+ userAdmin: userAdminReducer,
};
export default combineReducers(reducerMap);
diff --git a/src/common/routeConfig.js b/src/common/routeConfig.js
index 9f3a5c5..ed85646 100644
--- a/src/common/routeConfig.js
+++ b/src/common/routeConfig.js
@@ -1,14 +1,16 @@
import { App } from '../features/home';
import { PageNotFound } from '../features/common';
-import homeRoute from '../features/home/route';
-import commonRoute from '../features/common/route';
import _ from 'lodash';
+import commonRoute from '../features/common/route';
+import homeRoute from '../features/home/route';
+import userAdminRoute from '../features/user-admin/route';
// NOTE: DO NOT CHANGE the 'childRoutes' name and the declaration pattern.
// This is used for Rekit cmds to register routes config for new features, and remove config when remove features, etc.
const childRoutes = [
homeRoute,
commonRoute,
+ userAdminRoute,
];
const routes = [{
diff --git a/src/features/user-admin/DefaultPage.js b/src/features/user-admin/DefaultPage.js
new file mode 100644
index 0000000..cdfb83c
--- /dev/null
+++ b/src/features/user-admin/DefaultPage.js
@@ -0,0 +1,39 @@
+import React, { Component } from 'react';
+import PropTypes from 'prop-types';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import * as actions from './redux/actions';
+
+export class DefaultPage extends Component {
+ static propTypes = {
+ userAdmin: PropTypes.object.isRequired,
+ actions: PropTypes.object.isRequired,
+ };
+
+ render() {
+ return (
+
+ Page Content: user-admin/DefaultPage
+
+ );
+ }
+}
+
+/* istanbul ignore next */
+function mapStateToProps(state) {
+ return {
+ userAdmin: state.userAdmin,
+ };
+}
+
+/* istanbul ignore next */
+function mapDispatchToProps(dispatch) {
+ return {
+ actions: bindActionCreators({ ...actions }, dispatch)
+ };
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(DefaultPage);
diff --git a/src/features/user-admin/DefaultPage.scss b/src/features/user-admin/DefaultPage.scss
new file mode 100644
index 0000000..8bcdafb
--- /dev/null
+++ b/src/features/user-admin/DefaultPage.scss
@@ -0,0 +1,5 @@
+@import '../../styles/mixins';
+
+.user-admin-default-page {
+
+}
diff --git a/src/features/user-admin/index.js b/src/features/user-admin/index.js
new file mode 100644
index 0000000..33522c8
--- /dev/null
+++ b/src/features/user-admin/index.js
@@ -0,0 +1 @@
+export { default as DefaultPage } from './DefaultPage';
diff --git a/src/features/user-admin/redux/actions.js b/src/features/user-admin/redux/actions.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/features/user-admin/redux/constants.js b/src/features/user-admin/redux/constants.js
new file mode 100644
index 0000000..e69de29
diff --git a/src/features/user-admin/redux/initialState.js b/src/features/user-admin/redux/initialState.js
new file mode 100644
index 0000000..9570e38
--- /dev/null
+++ b/src/features/user-admin/redux/initialState.js
@@ -0,0 +1,11 @@
+// Initial state is the place you define all initial values for the Redux store of the feature.
+// In the 'standard' way, initialState is defined in reducers: http://redux.js.org/docs/basics/Reducers.html
+// But when application grows, there will be multiple reducers files, it's not intuitive what data is managed by the whole store.
+// So Rekit extracts the initial state definition into a separate module so that you can have
+// a quick view about what data is used for the feature, at any time.
+
+// NOTE: initialState constant is necessary so that Rekit could auto add initial state when creating async actions.
+const initialState = {
+};
+
+export default initialState;
diff --git a/src/features/user-admin/redux/reducer.js b/src/features/user-admin/redux/reducer.js
new file mode 100644
index 0000000..c9b022b
--- /dev/null
+++ b/src/features/user-admin/redux/reducer.js
@@ -0,0 +1,23 @@
+// This is the root reducer of the feature. It is used for:
+// 1. Load reducers from each action in the feature and process them one by one.
+// Note that this part of code is mainly maintained by Rekit, you usually don't need to edit them.
+// 2. Write cross-topic reducers. If a reducer is not bound to some specific action.
+// Then it could be written here.
+// Learn more from the introduction of this approach:
+// https://medium.com/@nate_wang/a-new-approach-for-managing-redux-actions-91c26ce8b5da.
+
+import initialState from './initialState';
+
+const reducers = [
+];
+
+export default function reducer(state = initialState, action) {
+ let newState;
+ switch (action.type) {
+ // Handle cross-topic actions here
+ default:
+ newState = state;
+ break;
+ }
+ return reducers.reduce((s, r) => r(s, action), newState);
+}
diff --git a/src/features/user-admin/route.js b/src/features/user-admin/route.js
new file mode 100644
index 0000000..cfeeb7c
--- /dev/null
+++ b/src/features/user-admin/route.js
@@ -0,0 +1,14 @@
+// This is the JSON way to define React Router rules in a Rekit app.
+// Learn more from: http://rekit.js.org/docs/routing.html
+
+import {
+ DefaultPage,
+} from './';
+
+export default {
+ path: 'user-admin',
+ name: 'User admin',
+ childRoutes: [
+ { path: 'default-page', name: 'Default page', component: DefaultPage, isIndex: true },
+ ],
+};
diff --git a/src/features/user-admin/style.scss b/src/features/user-admin/style.scss
new file mode 100644
index 0000000..743e0a3
--- /dev/null
+++ b/src/features/user-admin/style.scss
@@ -0,0 +1,2 @@
+@import '../../styles/mixins';
+@import './DefaultPage';
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 451a46d..fd4a49a 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -2,3 +2,4 @@
@import './global';
@import '../features/home/style';
@import '../features/common/style';
+@import '../features/user-admin/style';
diff --git a/tests/features/user-admin/DefaultPage.test.js b/tests/features/user-admin/DefaultPage.test.js
new file mode 100644
index 0000000..1bd50f7
--- /dev/null
+++ b/tests/features/user-admin/DefaultPage.test.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import { DefaultPage } from '../../../src/features/user-admin/DefaultPage';
+
+describe('user-admin/DefaultPage', () => {
+ it('renders node with correct class name', () => {
+ const props = {
+ userAdmin: {},
+ actions: {},
+ };
+ const renderedComponent = shallow(
+
+ );
+
+ expect(
+ renderedComponent.find('.user-admin-default-page').length
+ ).toBe(1);
+ });
+});
diff --git a/tests/features/user-admin/redux/reducer.test.js b/tests/features/user-admin/redux/reducer.test.js
new file mode 100644
index 0000000..5c40f67
--- /dev/null
+++ b/tests/features/user-admin/redux/reducer.test.js
@@ -0,0 +1,14 @@
+import reducer from '../../../../src/features/user-admin/redux/reducer';
+
+describe('user-admin/redux/reducer', () => {
+ it('does nothing if no matched action', () => {
+ const prevState = {};
+ const state = reducer(
+ prevState,
+ { type: '__UNKNOWN_ACTION_TYPE__' }
+ );
+ expect(state).toBe(prevState);
+ });
+
+ // TODO: add global reducer test if needed.
+});