",
7 | "license": "MIT",
8 | "dependencies": {
9 | "react": "^16.2.0",
10 | "react-dom": "^16.2.0",
11 | "react-redux": "^5.0.6",
12 | "react-router": "^4.2.2",
13 | "react-router-dom": "^4.2.2",
14 | "react-scripts": "1.0.13",
15 | "redux": "^3.7.2",
16 | "redux-observable": "^0.18.0",
17 | "rxjs": "^5.5.6"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test --env=jsdom",
23 | "eject": "react-scripts eject"
24 | }
25 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MuhammadMohsin/redux-boiler/f126824ab98be843e6615cc4201131c83f92a49e/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | Wealth Tab
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/components/App/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class App extends Component {
4 | render() {
5 | return (Parent
);
6 | }
7 | }
8 |
9 | export default App;
10 |
--------------------------------------------------------------------------------
/src/components/Dashboard/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Home extends Component {
4 | render() {
5 | return (
6 |
7 |
Welcome to Dashboard
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Home;
--------------------------------------------------------------------------------
/src/components/Signin/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Signin extends Component {
4 | constructor(props){
5 | super();
6 | }
7 | render() {
8 | return (
9 |
10 |
Login screen
11 |
15 |
16 | );
17 | }
18 | }
19 |
20 | export default Signin;
--------------------------------------------------------------------------------
/src/components/Signup/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class Signup extends Component {
4 | render() {
5 | return (
6 |
7 |
This is signup
8 |
9 | );
10 | }
11 | }
12 |
13 | export default Signup;
--------------------------------------------------------------------------------
/src/components/index.js:
--------------------------------------------------------------------------------
1 | import App from './App/index';
2 | import Signin from './Signin/index';
3 | import Signup from './Signup/index';
4 | import Home from './Dashboard/index';
5 |
6 | export {
7 | App,
8 | Signin,
9 | Signup,
10 | Home
11 | };
--------------------------------------------------------------------------------
/src/config/AppRoutes.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import {
3 | BrowserRouter,
4 | Route
5 | } from 'react-router-dom'
6 |
7 | import {
8 | App,
9 | Signup,
10 | Home
11 | } from './../components/index';
12 |
13 | import {
14 | Signin
15 | } from './../container/index';
16 |
17 | const ParentApp = () => (
18 |
19 |
20 |
21 | {/* App routing goes here!! */}
22 |
23 |
24 |
25 |
26 |
27 | );
28 |
29 | const AppRoutes = () => {
30 | return (
31 |
32 |
33 |
34 | )
35 | };
36 |
37 | export default AppRoutes;
--------------------------------------------------------------------------------
/src/config/path.js:
--------------------------------------------------------------------------------
1 | export default class path {
2 |
3 | static environment = "dev";
4 | // static environment = "prod";
5 | static baseUrl = this.environment === "dev" ? "" : "https://abc.com/";
6 |
7 | //authentication URL
8 | static SIGNUP = this.baseUrl + "api/user/signup";
9 | static LOGIN = "https://jsonplaceholder.typicode.com/posts"; // temp for now
10 |
11 | }
--------------------------------------------------------------------------------
/src/container/Signin/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | // import { browserHistory } from 'react-router';
4 | import { AuthActions } from "../../store/actions/index";
5 | import { Signin } from './../../components/index';
6 |
7 | class Login extends Component {
8 |
9 | constructor(props){
10 | super();
11 | }
12 |
13 | componentWillReceiveProps(nextProps) {
14 | console.log(nextProps);
15 | console.log(123)
16 | }
17 |
18 | loginSubmit = (user) => {
19 | this.props.signin(user);
20 | }
21 |
22 | render() {
23 | return (
24 |
25 | );
26 | }
27 | }
28 |
29 | const mapStateToProps = (state) => {
30 | return { userAuth: state.AuthReducer };
31 | };
32 | const mapDispatchToProps = (dispatch) => {
33 | return {
34 | signin: (userObj) => dispatch(AuthActions.signin(userObj))
35 | };
36 | };
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Login);
--------------------------------------------------------------------------------
/src/container/index.js:
--------------------------------------------------------------------------------
1 | import Signin from './Signin/index';
2 |
3 | export {
4 | Signin
5 | };
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import { store } from './store/index';
5 | import AppRoutes from './config/AppRoutes';
6 | import registerServiceWorker from './registerServiceWorker';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
15 | registerServiceWorker();
16 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (!isLocalhost) {
36 | // Is not local host. Just register service worker
37 | registerValidSW(swUrl);
38 | } else {
39 | // This is running on localhost. Lets check if a service worker still exists or not.
40 | checkValidServiceWorker(swUrl);
41 | }
42 | });
43 | }
44 | }
45 |
46 | function registerValidSW(swUrl) {
47 | navigator.serviceWorker
48 | .register(swUrl)
49 | .then(registration => {
50 | registration.onupdatefound = () => {
51 | const installingWorker = registration.installing;
52 | installingWorker.onstatechange = () => {
53 | if (installingWorker.state === 'installed') {
54 | if (navigator.serviceWorker.controller) {
55 | // At this point, the old content will have been purged and
56 | // the fresh content will have been added to the cache.
57 | // It's the perfect time to display a "New content is
58 | // available; please refresh." message in your web app.
59 | console.log('New content is available; please refresh.');
60 | } else {
61 | // At this point, everything has been precached.
62 | // It's the perfect time to display a
63 | // "Content is cached for offline use." message.
64 | console.log('Content is cached for offline use.');
65 | }
66 | }
67 | };
68 | };
69 | })
70 | .catch(error => {
71 | console.error('Error during service worker registration:', error);
72 | });
73 | }
74 |
75 | function checkValidServiceWorker(swUrl) {
76 | // Check if the service worker can be found. If it can't reload the page.
77 | fetch(swUrl)
78 | .then(response => {
79 | // Ensure service worker exists, and that we really are getting a JS file.
80 | if (
81 | response.status === 404 ||
82 | response.headers.get('content-type').indexOf('javascript') === -1
83 | ) {
84 | // No service worker found. Probably a different app. Reload the page.
85 | navigator.serviceWorker.ready.then(registration => {
86 | registration.unregister().then(() => {
87 | window.location.reload();
88 | });
89 | });
90 | } else {
91 | // Service worker found. Proceed as normal.
92 | registerValidSW(swUrl);
93 | }
94 | })
95 | .catch(() => {
96 | console.log(
97 | 'No internet connection found. App is running in offline mode.'
98 | );
99 | });
100 | }
101 |
102 | export function unregister() {
103 | if ('serviceWorker' in navigator) {
104 | navigator.serviceWorker.ready.then(registration => {
105 | registration.unregister();
106 | });
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/src/services/http.js:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs/Observable';
2 | import 'rxjs/add/observable/dom/ajax';
3 |
4 | export class HttpService {
5 | //Get request HTTP service
6 | static get(url, headers= {}){
7 | return Observable.ajax({
8 | url,
9 | method: 'GET',
10 | async: true,
11 | crossDomain: true,
12 | responseType: 'json',
13 | createXHR: () => new XMLHttpRequest()
14 | });
15 | }
16 | //Post request HTTP service
17 | static post(url, body, headers = { 'Content-Type': 'application/json' }) {
18 | return Observable.ajax({
19 | url,
20 | method: 'POST',
21 | body,
22 | headers,
23 | async: true,
24 | crossDomain: true,
25 | responseType: 'json',
26 | createXHR: () => new XMLHttpRequest()
27 | });
28 | }
29 | }
--------------------------------------------------------------------------------
/src/store/actions/authActions.js:
--------------------------------------------------------------------------------
1 | import {
2 | SIGNUP, SIGNUP_SUCCESS, SIGNUP_FAILURE,
3 | SIGNIN, SIGNIN_SUCCESS, SIGNIN_FAILURE,
4 | LOGOUT, LOGOUT_SUCCESS, LOGOUT_FAILURE
5 | } from '../constants'
6 |
7 | export default class AuthActions {
8 |
9 | static signup(user) {
10 | return {
11 | type: SIGNUP,
12 | payload: user
13 | }
14 | }
15 |
16 | static signupSuccess(data) {
17 | return {
18 | type: SIGNUP_SUCCESS,
19 | payload: data
20 | }
21 | }
22 |
23 | static signupFailure(error) {
24 | return {
25 | type: SIGNUP_FAILURE,
26 | error: error
27 | }
28 | }
29 |
30 | static signin(user) {
31 | return {
32 | type: SIGNIN,
33 | payload: user
34 | }
35 | }
36 |
37 | static signinSuccess(data) {
38 | return {
39 | type: SIGNIN_SUCCESS,
40 | payload: data
41 | }
42 | }
43 |
44 | static signinFailure(error) {
45 | return {
46 | type: SIGNIN_FAILURE,
47 | error: error
48 | }
49 | }
50 |
51 | static logout() {
52 | return {
53 | type: LOGOUT
54 | }
55 | }
56 |
57 | static logoutSuccess() {
58 | return {
59 | type: LOGOUT_SUCCESS
60 | }
61 | }
62 |
63 | static logoutFailure(error) {
64 | return {
65 | type: LOGOUT_FAILURE,
66 | error: error
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/src/store/actions/index.js:
--------------------------------------------------------------------------------
1 | import AuthActions from './authActions'
2 |
3 | export {
4 | AuthActions
5 | }
--------------------------------------------------------------------------------
/src/store/constants.js:
--------------------------------------------------------------------------------
1 | export const SIGNUP = 'SIGNUP'
2 | export const SIGNUP_SUCCESS = 'SIGNUP_SUCCESS'
3 | export const SIGNUP_FAILURE = 'SIGNUP_FAILURE'
4 |
5 | export const SIGNIN = 'SIGNIN'
6 | export const SIGNIN_SUCCESS = 'SIGNIN_SUCCESS'
7 | export const SIGNIN_FAILURE = 'SIGNIN_FAILURE'
8 |
9 | export const LOGOUT = 'LOGOUT'
10 | export const LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'
11 | export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'
12 |
--------------------------------------------------------------------------------
/src/store/epics/authEpic.js:
--------------------------------------------------------------------------------
1 | import {
2 | SIGNUP, SIGNUP_SUCCESS, SIGNUP_FAILURE,
3 | SIGNIN, SIGNIN_SUCCESS, SIGNIN_FAILURE
4 | } from '../constants'
5 | import 'rxjs';
6 | import { Observable } from 'rxjs';
7 | import { HttpService } from './../../services/http';
8 | import Path from './../../config/path';
9 |
10 | //** Epic Middlewares For Auth **//
11 | export default class AuthEpic {
12 |
13 | //Epic middleware for login
14 | static signinEpic = (action$) =>
15 | action$.ofType(SIGNIN)
16 | .switchMap(({ payload }) => {
17 | return HttpService.post(Path.LOGIN, payload)
18 | .switchMap(({ response }) => {
19 | console.log(response)
20 | if (response) {
21 | return Observable.of({
22 | type: SIGNIN_SUCCESS,
23 | payload: response
24 |
25 | });
26 | }
27 | return Observable.of({
28 | type: SIGNIN_FAILURE,
29 | payload: "email and password not matched ! Try Again "
30 | });
31 | });
32 | })
33 |
34 | //Epic middleware for signup
35 | static signupEpic = (action$) =>
36 | action$.ofType(SIGNUP)
37 | .switchMap(({ payload }) => {
38 | return HttpService.post(Path.SIGNUP, payload)
39 | .switchMap(({ response }) => {
40 | if (response.err) {
41 | return Observable.of({
42 | type: SIGNUP_FAILURE,
43 | payload: response.err
44 | });
45 | }
46 | return Observable.of({
47 | type: SIGNUP_SUCCESS,
48 | payload: response
49 | });
50 | });
51 | })
52 | }
--------------------------------------------------------------------------------
/src/store/epics/index.js:
--------------------------------------------------------------------------------
1 | import { combineEpics } from 'redux-observable';
2 |
3 | import AuthEpic from './authEpic'
4 |
5 | const rootEpic = combineEpics(
6 | AuthEpic.signupEpic,
7 | AuthEpic.signinEpic
8 | );
9 |
10 | export default rootEpic;
--------------------------------------------------------------------------------
/src/store/index.js:
--------------------------------------------------------------------------------
1 | import { createStore, applyMiddleware } from 'redux'
2 | import { createEpicMiddleware } from 'redux-observable'
3 |
4 | import rootReducer from './reducers'
5 | import rootEpic from './epics'
6 |
7 | // For initialize in application
8 | const epicMiddleware = createEpicMiddleware(rootEpic)
9 |
10 | function configureStore() {
11 | return createStore(rootReducer, applyMiddleware(epicMiddleware));
12 | }
13 |
14 | export const store = configureStore();
--------------------------------------------------------------------------------
/src/store/reducers/authReducer.js:
--------------------------------------------------------------------------------
1 | import {
2 | SIGNUP, SIGNUP_SUCCESS, SIGNUP_FAILURE,
3 | SIGNIN, SIGNIN_SUCCESS, SIGNIN_FAILURE,
4 | LOGOUT, LOGOUT_SUCCESS, LOGOUT_FAILURE
5 | } from '../constants'
6 | const initialState = {
7 | user: {},
8 | authUser: {},
9 | isLoading: false,
10 | isError: false,
11 | error: {},
12 | isLoggedIn: false,
13 | }
14 |
15 | export default function authReducer(state = initialState, action) {
16 | switch (action.type) {
17 | case SIGNUP:
18 | return {
19 | ...state,
20 | authUser: {},
21 | user: {},
22 | isLoading: true,
23 | isError: false,
24 | error: {},
25 | isLoggedIn: false,
26 | }
27 | case SIGNUP_SUCCESS:
28 | return {
29 | ...state,
30 | authUser: action.payload,
31 | isLoading: false,
32 | }
33 | case SIGNUP_FAILURE:
34 | return {
35 | ...state,
36 | isLoading: false,
37 | isError: true,
38 | error: action.error
39 | }
40 | case SIGNIN:
41 | return {
42 | ...state,
43 | user: {},
44 | authUser: {},
45 | isLoading: true,
46 | isError: false,
47 | error: {},
48 | isLoggedIn: false,
49 | }
50 | case SIGNIN_SUCCESS:
51 | return {
52 | ...state,
53 | user: action.payload,
54 | authUser: action.payload,
55 | isLoading: false,
56 | isLoggedIn: true,
57 | }
58 | case SIGNIN_FAILURE:
59 | return {
60 | ...state,
61 | isLoading: false,
62 | isError: true,
63 | error: action.error
64 | }
65 | case LOGOUT:
66 | return {
67 | ...state,
68 | isLoading: true
69 | }
70 | case LOGOUT_SUCCESS:
71 | return {
72 | ...state,
73 | authUser: {},
74 | user: {},
75 | isLoading: false,
76 | isError: false,
77 | error: {},
78 | isLoggedIn: false,
79 | }
80 | case LOGOUT_FAILURE:
81 | return {
82 | ...state,
83 | isLoading: false,
84 | isError: true,
85 | error: action.error
86 | }
87 | default:
88 | return state
89 | }
90 | }
--------------------------------------------------------------------------------
/src/store/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux'
2 | import authReducer from './authReducer'
3 |
4 | const rootReducer = combineReducers({
5 | userAuth: authReducer
6 | })
7 |
8 | export default rootReducer
--------------------------------------------------------------------------------