diff options
author | Indrajith K L | 2019-12-12 19:31:50 +0530 |
---|---|---|
committer | Indrajith K L | 2019-12-12 19:31:50 +0530 |
commit | 8883eacd2a5e2f3f5637a6b71123dfcb2a64c3d5 (patch) | |
tree | fe0fb8f601f2272f9bf2a7d2b365c7812acb6e63 /src | |
parent | f41d980fd83ab7da5804efd8aa7e914e820797d6 (diff) | |
download | react-redux-saga-starter-8883eacd2a5e2f3f5637a6b71123dfcb2a64c3d5.tar.gz react-redux-saga-starter-8883eacd2a5e2f3f5637a6b71123dfcb2a64c3d5.tar.bz2 react-redux-saga-starter-8883eacd2a5e2f3f5637a6b71123dfcb2a64c3d5.zip |
:fire: :zap: Major Update
* Adds Actions, Redicers and Middlewares
* Adds Http Service
* Adds Cancel option for Http Service
* Adds HOC's for API Loader, Sidebar and Headers
* Adds Random key generator for Routes
Diffstat (limited to 'src')
32 files changed, 662 insertions, 51 deletions
diff --git a/src/actions/login.action.js b/src/actions/login.action.js new file mode 100644 index 0000000..3468e4e --- /dev/null +++ b/src/actions/login.action.js @@ -0,0 +1,16 @@ +import { LOGIN_REQUEST, LOGIN_SUCCESS } from "../utils/constants"; + + +export const loginRequest = (payload)=>{ + return { + type: LOGIN_REQUEST, + ...payload + }; +} + +export const loginSuccess = (payload)=>{ + return { + type: LOGIN_SUCCESS, + ...payload + }; +}
\ No newline at end of file diff --git a/src/core/app.routes.js b/src/core/app.routes.js index 5d06e63..b581d2e 100644 --- a/src/core/app.routes.js +++ b/src/core/app.routes.js @@ -1,5 +1,6 @@ import AdminContainer from "../modules/admin/admin.container"; import SuperAdminContainer from "../modules/superadmin/superadmin.container"; +import DashBoardContainer from "../modules/dashboard/dashboard.container"; export const AppRoutes = [ { @@ -11,5 +12,10 @@ export const AppRoutes = [ path: '/superadmin', component: SuperAdminContainer, permission: ['admin', 'superadmin', 'user'] + }, + { + path: '/dashboard', + component: DashBoardContainer, + permission: ['user'] } ]; diff --git a/src/core/custom.router.js b/src/core/custom.router.js index c6b2859..9fcd4f6 100644 --- a/src/core/custom.router.js +++ b/src/core/custom.router.js @@ -1,6 +1,8 @@ import React from "react"; import { Route, Redirect } from "react-router-dom"; import Storage from "../services/storage.service"; +import Permissions from "./permission.router"; +import { RandomKey } from "../utils/random.key"; export const CustomRouter = ({ xComponent: Component, ...xProps }) => { return ( @@ -19,7 +21,7 @@ export const CustomRouter = ({ xComponent: Component, ...xProps }) => { return <Redirect to="/dashboard" />; } - return <Component {...returnProps} />; + return <Permissions {...returnProps} key={RandomKey.generate()} Component={Component}/>; }} /> ); diff --git a/src/core/permission.router.js b/src/core/permission.router.js index 4047b75..d698917 100644 --- a/src/core/permission.router.js +++ b/src/core/permission.router.js @@ -1,4 +1,19 @@ import React from "react"; import { Route, Redirect } from "react-router-dom"; -// export const Permi
\ No newline at end of file +export const Permissions = ({Component: Component, ..._props})=>{ + + return ( + <Route + render={props => { + let returnProps = {..._props, ...props}; + // let token = Storage.get("token"); + let pathName = props.match.path; + console.log(returnProps); + return <Component {...returnProps} />; + }} + /> + ); +} + +export default Permissions;
\ No newline at end of file diff --git a/src/core/routes.js b/src/core/routes.js index 764e793..9c2d222 100644 --- a/src/core/routes.js +++ b/src/core/routes.js @@ -1,33 +1,36 @@ import React, { Suspense } from "react"; -import { Provider } from "react-redux"; +import { Provider, connect } from "react-redux"; import { ConnectedRouter } from "connected-react-router"; -import { Switch, Redirect, Route } from "react-router-dom"; +import { Switch, Redirect, Route, withRouter } from "react-router-dom"; import { CustomRouter } from "./custom.router"; import LoginContainer from "../modules/login/login.container"; import DashBoardContainer from "../modules/dashboard/dashboard.container"; import { AppRoutes } from "./app.routes"; +import MasterComponent from "../master/master.component"; const Routes = ({ store, history }) => { return ( <Provider store={store}> - <ConnectedRouter history={history}> - <Suspense - fallback={<div style={{ display: "none" }}> Loading ...</div>} - > - <Switch> - <CustomRouter path="/login" xComponent={LoginContainer} /> - <CustomRouter path="/dashboard" xComponent={DashBoardContainer} /> - {AppRoutes.map(_routes => - <CustomRouter - key={_routes.path} - path={_routes.path} - xComponent={_routes.component} - permissions={_routes.permission} - />)} - <Redirect from="*" to="/login" push /> - </Switch> - </Suspense> - </ConnectedRouter> + <MasterComponent> + <ConnectedRouter history={history}> + <Suspense + fallback={<div style={{ display: "none" }}> Loading ...</div>} + > + <Switch> + <CustomRouter path="/login" xComponent={LoginContainer} /> + <CustomRouter path="/dashboard" xComponent={DashBoardContainer} /> + {AppRoutes.map(_routes => + <CustomRouter + key={_routes.path} + path={_routes.path} + xComponent={_routes.component} + permissions={_routes.permission} + />)} + <Redirect from="*" to="/login" push /> + </Switch> + </Suspense> + </ConnectedRouter> + </MasterComponent> </Provider> ); }; diff --git a/src/index.css b/src/index.css index 1532074..0d4c466 100644 --- a/src/index.css +++ b/src/index.css @@ -6,3 +6,18 @@ body { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } + + +html, body { + margin:0; + padding:0; + height:100%; +} + +.container-fluid{ + height: 100%; +} + +.content{ + margin-left: 92px; +}
\ No newline at end of file diff --git a/src/index.js b/src/index.js index a3b342f..787b0c1 100644 --- a/src/index.js +++ b/src/index.js @@ -11,6 +11,7 @@ import { Route } from "react-router-dom"; import Routes from './core/routes'; +import HttpService from './services/http.service'; require("es6-promise").polyfill(); @@ -18,6 +19,9 @@ require("es6-promise").polyfill(); const store = configureStore(); store.runSaga(rootMiddleware); +HttpService.reduxStore = store; +HttpService.httpInterceptor(); +// console.log(HttpService.httpInterceptor) const XRouter = () => { return ( diff --git a/src/master/master.component.js b/src/master/master.component.js new file mode 100644 index 0000000..703badf --- /dev/null +++ b/src/master/master.component.js @@ -0,0 +1,36 @@ +import React from 'react'; +import { createLoadingSelector, createNotificationSelector } from '../services/selectors'; +import WithLoader from '../shared/loader.hoc'; +import { connect } from "react-redux"; + +let loadingSelector = createLoadingSelector([ + 'LOGIN', + 'COMMON' +]); + +let errorSelector = createNotificationSelector([ + 'LOGIN', + 'COMMON' +]); + +const MasterComponent = (props) => { + + return ( + <> + {props.children} + </> + ); +} + + +const mapStateToProps = state => { + return { + isLoading: loadingSelector(state), + error: errorSelector(state) + }; +}; + +export default connect(mapStateToProps)( + WithLoader(MasterComponent) +); + diff --git a/src/middlewares/login.middleware.js b/src/middlewares/login.middleware.js new file mode 100644 index 0000000..c4dbc5b --- /dev/null +++ b/src/middlewares/login.middleware.js @@ -0,0 +1,29 @@ +import { put, call, fork, takeEvery } from "redux-saga/effects"; +import { LOGIN_REQUEST, LOGIN_SUCCESS } from "../utils/constants"; +import { loginMock } from "../modules/login/login.service"; +import { history } from '../core/store'; +function* loginWatcher() { + yield takeEvery(LOGIN_REQUEST, loginWorker); +} + +function* loginWorker(action) { + let { email, password } = action; + let res = yield call(loginApi, { email, password }); + if (res && res.data) { + let { token } = res.data; + yield put({ + type: LOGIN_SUCCESS, + payload: { + token + } + }); + history.push('/dashboard'); + } + console.log(res); +} + +function loginApi(params) { + return loginMock(params); +} + +export const LoginSaga = [fork(loginWatcher)];
\ No newline at end of file diff --git a/src/middlewares/root.middleware.js b/src/middlewares/root.middleware.js index 2e90582..065a572 100644 --- a/src/middlewares/root.middleware.js +++ b/src/middlewares/root.middleware.js @@ -1,7 +1,8 @@ import { all } from "redux-saga/effects"; +import { LoginSaga } from "./login.middleware"; export default function* rootMiddleware() { yield all([ - //...LoginSaga, + ...LoginSaga, ]); }
\ No newline at end of file diff --git a/src/modules/admin/admin.container.js b/src/modules/admin/admin.container.js index bd6e1dc..91b0d1c 100644 --- a/src/modules/admin/admin.container.js +++ b/src/modules/admin/admin.container.js @@ -1,16 +1,33 @@ -import React, {Component} from 'react'; - -class AdminContainer extends Component{ - constructor(props){ +import React, { Component } from 'react'; +import { connect } from "react-redux"; +import WithHeaderFooter from '../../shared/header_footer.hoc'; +import WithSidebar from '../../shared/sidebar.hoc'; +class AdminContainer extends Component { + constructor(props) { console.log(props); super(props); } - render(){ - return( - <div>Admin Container</div> + render() { + return ( + <div className="container-fluid"> + <div className="row"> + <div className="col-md-12"> + Admin Container + </div> + </div> + </div> ); } } -export default AdminContainer;
\ No newline at end of file +const mapStateToProps = state => { + return { + + }; +}; + + +export default connect(mapStateToProps)( + WithSidebar(WithHeaderFooter(AdminContainer)) +);
\ No newline at end of file diff --git a/src/modules/dashboard/dashboard.container.js b/src/modules/dashboard/dashboard.container.js index 595aa9f..f792c20 100644 --- a/src/modules/dashboard/dashboard.container.js +++ b/src/modules/dashboard/dashboard.container.js @@ -1,12 +1,28 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; +import { connect } from "react-redux"; +import WithHeaderFooter from '../../shared/header_footer.hoc'; +import WithSidebar from '../../shared/sidebar.hoc'; +class DashBoardContainer extends Component { -class DashBoardContainer extends Component{ - - render(){ - return( - <div>Dashboard</div> + render() { + return ( + <div className="container-fluid"> + <div className="row"> + <div className="col-md-12"> + Dashboard + </div> + </div> + </div> ); } } -export default DashBoardContainer;
\ No newline at end of file +const mapStateToProps = state => { + return { + + }; +}; + +export default connect(mapStateToProps)( + WithSidebar(WithHeaderFooter(DashBoardContainer)) +);
\ No newline at end of file diff --git a/src/modules/login/login.container.js b/src/modules/login/login.container.js index 705284e..2bf05b1 100644 --- a/src/modules/login/login.container.js +++ b/src/modules/login/login.container.js @@ -1,12 +1,50 @@ -import React,{Component} from 'react'; +import React, { Component } from 'react'; +import { connect } from "react-redux"; +import WithFooter from '../../shared/footer.hoc'; +import { loginMock } from './login.service'; +import { loginRequest } from '../../actions/login.action'; +import HttpService from '../../services/http.service'; +class LoginContainer extends Component { -class LoginContainer extends Component{ + state = { - render(){ - return( - <div>Login</div> + }; + + onLogin = ()=>{ + let params = { + email: "eve.holt@reqres.in", + password: "cityslicka" + }; + + // loginMock(params).then(res=>{ + // console.log(res); + // }) + this.props.dispatch(loginRequest(params)); + // HttpService.cancelRequest(); + } + + render() { + return ( + <div className="container-fluid"> + <div className="row"> + <div className="col-md-12"> + Login + </div> + <div className="col-md-12"> + <button className="btn btn-primary" onClick={this.onLogin}>Login</button> + </div> + </div> + </div> ); } } -export default LoginContainer;
\ No newline at end of file +const mapStateToProps = state => { + return { + + }; +}; + +export default connect(mapStateToProps)( + WithFooter(LoginContainer) +);
\ No newline at end of file diff --git a/src/modules/login/login.service.js b/src/modules/login/login.service.js new file mode 100644 index 0000000..15fc3cc --- /dev/null +++ b/src/modules/login/login.service.js @@ -0,0 +1,9 @@ +import HttpService from '../../services/http.service'; + +export const loginMock = (params)=>{ + return HttpService.fetch({ + url: 'https://reqres.in/api/login', + method: 'post', + data: params + }); +}
\ No newline at end of file diff --git a/src/modules/superadmin/superadmin.container.js b/src/modules/superadmin/superadmin.container.js index a82608d..ef83a52 100644 --- a/src/modules/superadmin/superadmin.container.js +++ b/src/modules/superadmin/superadmin.container.js @@ -1,12 +1,57 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; +import { connect } from "react-redux"; +import WithHeaderFooter from '../../shared/header_footer.hoc'; +import WithSidebar from '../../shared/sidebar.hoc'; +import { COMMON_REQUEST, COMMON_CANCEL } from '../../utils/constants'; +import HttpService from '../../services/http.service'; +class SuperAdminContainer extends Component { -class SuperAdminContainer extends Component{ + componentDidMount() { - render(){ - return( - <div>SuperAdminContainer</div> + } + + startRequest = () => { + this.props.dispatch({ + type: COMMON_REQUEST + }); + let params = { + url: 'https://reqres.in/api/users?page=2' + } + HttpService.fetch(params).then(res=>{ + console.log(res); + }) + } + + stopRequest = () => { + // this.props.dispatch({ + // type: COMMON_CANCEL + // }) + HttpService.cancelRequest(); + } + + render() { + return ( + <div className="container-fluid"> + <div className="row"> + <div className="col-md-12"> + SuperAdminContainer + </div> + </div> + <div className="row"> + <div className="col-md-1"><button className="btn btn-primary" onClick={this.startRequest}>Start Request</button></div> + <div className="col-md-1"><button className="btn btn btn-danger" onClick={this.stopRequest}>Stop Request</button></div> + </div> + </div> ); } } -export default SuperAdminContainer;
\ No newline at end of file +const mapStateToProps = state => { + return { + + }; +}; + +export default connect(mapStateToProps)( + WithSidebar(WithHeaderFooter(SuperAdminContainer)) +);
\ No newline at end of file diff --git a/src/reducers/error.reducer.js b/src/reducers/error.reducer.js new file mode 100644 index 0000000..83d1128 --- /dev/null +++ b/src/reducers/error.reducer.js @@ -0,0 +1,18 @@ +export default function ErrorReducer(state = {}, action) { + const { type, error } = action; + const matches = /(.*)_(REQUEST|FAILED|ERROR)/.exec( + type + ); + if (!matches) return state; + const [, requestName, requestState] = matches; + return { + errorMessage: + requestState === "FAILED" || requestState === "ERROR" + ? error + ? error + : "" + : "", + [requestName]: requestState === "FAILED" || requestState === "ERROR" ? true: false + }; + } +
\ No newline at end of file diff --git a/src/reducers/loading.reducer.js b/src/reducers/loading.reducer.js new file mode 100644 index 0000000..5ff7651 --- /dev/null +++ b/src/reducers/loading.reducer.js @@ -0,0 +1,12 @@ +export default function LoadingReducer(state = {}, action) { + console.log("Reducer",action) + const { type } = action; + const matches = /(.*)_(REQUEST|SUCCESS|FAILED|ERROR|SUBMIT|CANCEL)/.exec(type); + if (!matches) return state; + const [, requestName, requestState] = matches; + return { + ...state, + [requestName]: (requestState === 'REQUEST' || requestState === 'SUBMIT') + }; + +}
\ No newline at end of file diff --git a/src/reducers/login.reducer.js b/src/reducers/login.reducer.js new file mode 100644 index 0000000..3229e35 --- /dev/null +++ b/src/reducers/login.reducer.js @@ -0,0 +1,21 @@ +import { LOGIN_REQUEST, LOGIN_SUCCESS } from "../utils/constants"; +import Storage from "../services/storage.service"; + + +let initialState = { + token: "" +}; + +export const LoginReducer = (state=initialState, action)=>{ + switch (action.type) { + case LOGIN_REQUEST: return state; + case LOGIN_SUCCESS: + + Storage.set('token', action.payload.token); + return { + ...state, + token: action.payload.token + }; + default: return state; + } +}
\ No newline at end of file diff --git a/src/reducers/root.reducer.js b/src/reducers/root.reducer.js index de1a3b8..c5796ea 100644 --- a/src/reducers/root.reducer.js +++ b/src/reducers/root.reducer.js @@ -1,9 +1,15 @@ import { combineReducers } from "redux"; import { connectRouter } from "connected-react-router"; +import LoadingReducer from "./loading.reducer"; +import ErrorReducer from "./error.reducer"; +import { LoginReducer } from "./login.reducer"; const createRootReducer = history => combineReducers({ router: connectRouter(history), + loading: LoadingReducer, + error: ErrorReducer, + login: LoginReducer }); export default createRootReducer; diff --git a/src/services/http.service.js b/src/services/http.service.js index e69de29..c3914f6 100644 --- a/src/services/http.service.js +++ b/src/services/http.service.js @@ -0,0 +1,90 @@ +import axios from 'axios'; +import Storage from './storage.service'; +import { COMMON_REQUEST, COMMON_SUCCESS, COMMON_CANCEL } from '../utils/constants'; + +class HttpServiceSingleton { + constructor() { + axios.defaults.headers.post["Content-Type"] = "application/json"; + axios.defaults.headers.put["Accept"] = "application/json"; + this.count = 0; // This will store API requests + this.complete = 0; // This will store API Success/errors + } + + set reduxStore(store) { + this.store = store; + } + + fetch(payload, noAuth) { + const cancelToken = axios.CancelToken; + this.cancelSource = cancelToken.source(); + let config = {}; + if (!noAuth) { + let token = Storage.get("token"); + config.headers = { + 'Authirization': `Bearer ${token}` + }; + } + + config.method = payload.method ? payload.method : 'get'; + config.url = payload.url ? payload.url : ''; + config.cancelToken = this.cancelSource.token; + if (payload.data) config.data = JSON.stringify(payload.data); + + return axios(config).catch((thrown) => { + if (axios.isCancel(thrown)) { + this.count = 0; + this.complete = 0; + this.store.dispatch({ + type: COMMON_CANCEL + }); + console.log('Request canceled', thrown.message); + } else { + // handle error + } + }); + } + + httpInterceptor() { + axios.interceptors.request.use((config) => { + this.count++; + this.checkApiComplete(this.store); + return config; + }, (error) => { + this.complete++; + this.checkApiComplete(this.store); + return Promise.reject(error); + }); + + axios.interceptors.response.use((response) => { + this.complete++; + this.checkApiComplete(this.store); + return response; + }, (error) => { + this.complete++; + this.checkApiComplete(this.store); + return Promise.reject(error); + }); + } + + cancelRequest() { + this.cancelSource.cancel(); + } + + //Fallback to cancel all API loaders in case of multiple API call occuts + checkApiComplete(store) { + if (this.count == this.complete) { // Cancel API loader when all requests are completed + store.dispatch({ + type: COMMON_SUCCESS + }); + } else { + store.dispatch({ + type: COMMON_REQUEST + }); + } + } +} + +const HttpService = new HttpServiceSingleton(); +// Object.freeze(HttpService); // Singleton Http Service + +export default HttpService;
\ No newline at end of file diff --git a/src/services/selectors.js b/src/services/selectors.js new file mode 100644 index 0000000..f9942d4 --- /dev/null +++ b/src/services/selectors.js @@ -0,0 +1,10 @@ +import _ from "lodash"; + +export const createLoadingSelector = actions => state => { + return _(actions).some(action => _.get(state, `loading.${action}`)); +}; + +export const createNotificationSelector = actions => state => { + return _(actions) + .some(action => _.get(state, `error.${action}`)); +}; diff --git a/src/services/storage.service.js b/src/services/storage.service.js index c41d552..d29a1e5 100644 --- a/src/services/storage.service.js +++ b/src/services/storage.service.js @@ -9,7 +9,8 @@ class Storage{ if(!key||!value){ throw("Storag.set expects a 'key' and a 'value' - 'value' & 'key' can't be null"); } - localStorage.setItem(key, JSON.stringify(value)); + value = (typeof value=="string") ? value : JSON.stringify(value); + localStorage.setItem(key, value); } } diff --git a/src/shared/footer.css b/src/shared/footer.css new file mode 100644 index 0000000..048b0c6 --- /dev/null +++ b/src/shared/footer.css @@ -0,0 +1,13 @@ +.footer { + position: absolute; + bottom: 0; + width: 95%; + height: 60px; + line-height: 60px; + background-color: #f5f5f5; +} + +.footer>.container { + padding-right: 15px; + padding-left: 15px; +}
\ No newline at end of file diff --git a/src/shared/footer.hoc.js b/src/shared/footer.hoc.js new file mode 100644 index 0000000..535a52d --- /dev/null +++ b/src/shared/footer.hoc.js @@ -0,0 +1,35 @@ +import React, { Component } from "react"; +import { Link } from 'react-router-dom'; +import { connect } from "react-redux"; +import { compose } from "redux"; +import './footer.css'; + +const Footer = (HocComponent) => { + return class FooterComponent extends Component { + + render() { + return ( + <React.Fragment> + <HocComponent {...this.props} /> + <footer className="footer"> + <div className="container">Footer</div> + </footer> + + </React.Fragment> + ); + } + } +} + + +const mapStateToProps = state => { + return { + + }; +}; + +const WithFooter = compose( + connect(mapStateToProps, null), + Footer +) +export default WithFooter;
\ No newline at end of file diff --git a/src/shared/header_footer.hoc.js b/src/shared/header_footer.hoc.js new file mode 100644 index 0000000..0c093a6 --- /dev/null +++ b/src/shared/header_footer.hoc.js @@ -0,0 +1,39 @@ +import React, { Component } from "react"; +import { Link } from 'react-router-dom'; +import { connect } from "react-redux"; +import { compose } from "redux"; + +const HeaderFooter = (HocComponent) => { + return class HeaderFooterComponent extends Component { + + render() { + return ( + <React.Fragment> + <nav className="nav"> + <Link className="nav-link" to={"/dashboard"} >Dashboard</Link> + <Link className="nav-link" to={"/superadmin"} >Superadmin</Link> + <Link className="nav-link" to={"/admin"} >Admin</Link> + <Link className="nav-link" to={"/login"} >Login</Link> + </nav> + <HocComponent {...this.props} /> + <footer className="footer"> + <div className="container">Footer</div> + </footer> + </React.Fragment> + ); + } + } +} + + +const mapStateToProps = state => { + return { + + }; +}; + +const WithHeaderFooter = compose( + connect(mapStateToProps, null), + HeaderFooter +) +export default WithHeaderFooter;
\ No newline at end of file diff --git a/src/shared/loader.css b/src/shared/loader.css new file mode 100644 index 0000000..2ee47a2 --- /dev/null +++ b/src/shared/loader.css @@ -0,0 +1,48 @@ +.loader { + position: absolute; + z-index: 6; + top: 0px; + left: 0; + height: 4px; + width: 100%; + overflow: hidden; + background-color: #ddd; + } + + .loader:before { + display: block; + position: absolute; + content: ""; + left: -200px; + width: 200px; + height: 4px; + background-color: #ff8373; + animation: loading 2s linear infinite; + } + + @keyframes loading { + from { + left: -200px; + width: 30%; + } + + 50% { + width: 30%; + } + + 70% { + width: 70%; + } + + 80% { + left: 50%; + } + + 95% { + left: 120%; + } + + to { + left: 100%; + } + }
\ No newline at end of file diff --git a/src/shared/loader.hoc.js b/src/shared/loader.hoc.js new file mode 100644 index 0000000..c60089e --- /dev/null +++ b/src/shared/loader.hoc.js @@ -0,0 +1,16 @@ +import React from 'react'; +import "./loader.css"; +const WithLoader = HocComponent => { + return function ({ ...props }) { + return ( + <div className="loader-container"> + {props.isLoading && ( + <div className="loader"></div> + )} + <HocComponent {...props} /> + </div> + ); + }; +}; + +export default WithLoader;
\ No newline at end of file diff --git a/src/shared/sidebar.css b/src/shared/sidebar.css new file mode 100644 index 0000000..cfb3e02 --- /dev/null +++ b/src/shared/sidebar.css @@ -0,0 +1,6 @@ +.sidebar{ + background: #cccc; + width: 92px; + height: calc(100vh); + position: absolute; +}
\ No newline at end of file diff --git a/src/shared/sidebar.hoc.js b/src/shared/sidebar.hoc.js new file mode 100644 index 0000000..30a18a3 --- /dev/null +++ b/src/shared/sidebar.hoc.js @@ -0,0 +1,36 @@ +import React, { Component } from "react"; +import { Link } from 'react-router-dom'; +import { connect } from "react-redux"; +import { compose } from "redux"; +import './sidebar.css'; + +const Sidebar = (HocComponent) => { + return class SidebarComponent extends Component { + + render() { + return ( + <React.Fragment> + <div className="sidebar"> + Sidebar + </div> + <div className="content"> + <HocComponent {...this.props} /> + </div> + </React.Fragment> + ); + } + } +} + + +const mapStateToProps = state => { + return { + + }; +}; + +const WithSidebar = compose( + connect(mapStateToProps, null), + Sidebar +) +export default WithSidebar;
\ No newline at end of file diff --git a/src/utils/constants.js b/src/utils/constants.js new file mode 100644 index 0000000..a7ae6de --- /dev/null +++ b/src/utils/constants.js @@ -0,0 +1,5 @@ +export const LOGIN_REQUEST = "LOGIN_REQUEST"; +export const LOGIN_SUCCESS = "LOGIN_SUCCESS"; +export const COMMON_REQUEST = "COMMON_REQUEST"; +export const COMMON_SUCCESS = "COMMON_SUCCESS"; +export const COMMON_CANCEL = "COMMON_CANCEL";
\ No newline at end of file diff --git a/src/utils/random.key.js b/src/utils/random.key.js new file mode 100644 index 0000000..50e5293 --- /dev/null +++ b/src/utils/random.key.js @@ -0,0 +1,3 @@ +export const RandomKey = { + generate : ()=> parseInt(Math.random()*Math.pow(10,12),10) +};
\ No newline at end of file diff --git a/src/shared/header.hoc.js b/src/utils/utls.js index e69de29..e69de29 100644 --- a/src/shared/header.hoc.js +++ b/src/utils/utls.js |