🔥 ⚡ 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
This commit is contained in:
16
src/actions/login.action.js
Normal file
16
src/actions/login.action.js
Normal file
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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']
|
||||
}
|
||||
];
|
||||
|
||||
@@ -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}/>;
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,19 @@
|
||||
import React from "react";
|
||||
import { Route, Redirect } from "react-router-dom";
|
||||
|
||||
// export const Permi
|
||||
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;
|
||||
@@ -1,15 +1,17 @@
|
||||
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}>
|
||||
<MasterComponent>
|
||||
<ConnectedRouter history={history}>
|
||||
<Suspense
|
||||
fallback={<div style={{ display: "none" }}> Loading ...</div>}
|
||||
@@ -28,6 +30,7 @@ const Routes = ({ store, history }) => {
|
||||
</Switch>
|
||||
</Suspense>
|
||||
</ConnectedRouter>
|
||||
</MasterComponent>
|
||||
</Provider>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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 (
|
||||
|
||||
36
src/master/master.component.js
Normal file
36
src/master/master.component.js
Normal file
@@ -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)
|
||||
);
|
||||
|
||||
29
src/middlewares/login.middleware.js
Normal file
29
src/middlewares/login.middleware.js
Normal file
@@ -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)];
|
||||
@@ -1,7 +1,8 @@
|
||||
import { all } from "redux-saga/effects";
|
||||
import { LoginSaga } from "./login.middleware";
|
||||
|
||||
export default function* rootMiddleware() {
|
||||
yield all([
|
||||
//...LoginSaga,
|
||||
...LoginSaga,
|
||||
]);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
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);
|
||||
@@ -8,9 +10,24 @@ class AdminContainer extends Component{
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>Admin Container</div>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
Admin Container
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default AdminContainer;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
export default connect(mapStateToProps)(
|
||||
WithSidebar(WithHeaderFooter(AdminContainer))
|
||||
);
|
||||
@@ -1,12 +1,28 @@
|
||||
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 {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>Dashboard</div>
|
||||
<div className="container-fluid">
|
||||
<div className="row">
|
||||
<div className="col-md-12">
|
||||
Dashboard
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DashBoardContainer;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(
|
||||
WithSidebar(WithHeaderFooter(DashBoardContainer))
|
||||
);
|
||||
@@ -1,12 +1,50 @@
|
||||
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 {
|
||||
|
||||
state = {
|
||||
|
||||
};
|
||||
|
||||
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>Login</div>
|
||||
<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;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(
|
||||
WithFooter(LoginContainer)
|
||||
);
|
||||
9
src/modules/login/login.service.js
Normal file
9
src/modules/login/login.service.js
Normal file
@@ -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
|
||||
});
|
||||
}
|
||||
@@ -1,12 +1,57 @@
|
||||
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 {
|
||||
|
||||
componentDidMount() {
|
||||
|
||||
}
|
||||
|
||||
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>SuperAdminContainer</div>
|
||||
<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;
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps)(
|
||||
WithSidebar(WithHeaderFooter(SuperAdminContainer))
|
||||
);
|
||||
18
src/reducers/error.reducer.js
Normal file
18
src/reducers/error.reducer.js
Normal file
@@ -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
|
||||
};
|
||||
}
|
||||
|
||||
12
src/reducers/loading.reducer.js
Normal file
12
src/reducers/loading.reducer.js
Normal file
@@ -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')
|
||||
};
|
||||
|
||||
}
|
||||
21
src/reducers/login.reducer.js
Normal file
21
src/reducers/login.reducer.js
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
10
src/services/selectors.js
Normal file
10
src/services/selectors.js
Normal file
@@ -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}`));
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
13
src/shared/footer.css
Normal file
13
src/shared/footer.css
Normal file
@@ -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;
|
||||
}
|
||||
35
src/shared/footer.hoc.js
Normal file
35
src/shared/footer.hoc.js
Normal file
@@ -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;
|
||||
39
src/shared/header_footer.hoc.js
Normal file
39
src/shared/header_footer.hoc.js
Normal file
@@ -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;
|
||||
48
src/shared/loader.css
Normal file
48
src/shared/loader.css
Normal file
@@ -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%;
|
||||
}
|
||||
}
|
||||
16
src/shared/loader.hoc.js
Normal file
16
src/shared/loader.hoc.js
Normal file
@@ -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;
|
||||
6
src/shared/sidebar.css
Normal file
6
src/shared/sidebar.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.sidebar{
|
||||
background: #cccc;
|
||||
width: 92px;
|
||||
height: calc(100vh);
|
||||
position: absolute;
|
||||
}
|
||||
36
src/shared/sidebar.hoc.js
Normal file
36
src/shared/sidebar.hoc.js
Normal file
@@ -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;
|
||||
5
src/utils/constants.js
Normal file
5
src/utils/constants.js
Normal file
@@ -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";
|
||||
3
src/utils/random.key.js
Normal file
3
src/utils/random.key.js
Normal file
@@ -0,0 +1,3 @@
|
||||
export const RandomKey = {
|
||||
generate : ()=> parseInt(Math.random()*Math.pow(10,12),10)
|
||||
};
|
||||
Reference in New Issue
Block a user