Sfoglia il codice sorgente

rework initial structure

Maxim 5 anni fa
parent
commit
2e840c1379

File diff suppressed because it is too large
+ 6192 - 3850
package-lock.json


+ 11 - 2
package.json

@@ -5,7 +5,13 @@
   "dependencies": {
     "react": "^16.6.3",
     "react-dom": "^16.6.3",
-    "react-scripts": "2.1.1"
+    "react-redux": "^6.0.0",
+    "react-router": "^4.3.1",
+    "react-router-dom": "^4.3.1",
+    "react-scripts": "^2.1.3",
+    "redux": "^4.0.1",
+    "redux-form": "^8.1.0",
+    "redux-saga": "^1.0.0"
   },
   "scripts": {
     "start": "react-scripts start",
@@ -21,5 +27,8 @@
     "not dead",
     "not ie <= 11",
     "not op_mini all"
-  ]
+  ],
+  "devDependencies": {
+    "redux-logger": "^3.0.6"
+  }
 }

BIN
public/favicon.ico


+ 22 - 35
public/index.html

@@ -1,40 +1,27 @@
 <!DOCTYPE html>
 <html lang="en">
-  <head>
-    <meta charset="utf-8">
-    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
-    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
-    <meta name="theme-color" content="#000000">
-    <!--
-      manifest.json provides metadata used when your web app is added to the
-      homescreen on Android. See https://developers.google.com/web/fundamentals/web-app-manifest/
-    -->
-    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
-    <!--
-      Notice the use of %PUBLIC_URL% in the tags above.
-      It will be replaced with the URL of the `public` folder during the build.
-      Only files inside the `public` folder can be referenced from the HTML.
 
-      Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
-      work correctly both with client-side routing and a non-root public URL.
-      Learn how to configure a non-root public URL by running `npm run build`.
-    -->
-    <title>React App</title>
-  </head>
-  <body>
-    <noscript>
-      You need to enable JavaScript to run this app.
-    </noscript>
-    <div id="root"></div>
-    <!--
-      This HTML file is a template.
-      If you open it directly in the browser, you will see an empty page.
+<head>
+  <meta charset="utf-8">
+  <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
+  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
+  <meta name="theme-color" content="#000000">
+  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
+    crossorigin="anonymous">
+  <title>React App</title>
+</head>
 
-      You can add webfonts, meta tags, or analytics to this file.
-      The build step will place the bundled scripts into the <body> tag.
+<body>
+  <noscript>
+    You need to enable JavaScript to run this app.
+  </noscript>
+  <div id="root"></div>
+  <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
+    crossorigin="anonymous"></script>
+  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"
+    crossorigin="anonymous"></script>
+  <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k"
+    crossorigin="anonymous"></script>
+</body>
 
-      To begin the development, run `npm start` or `yarn start`.
-      To create a production bundle, use `npm run build` or `yarn build`.
-    -->
-  </body>
-</html>
+</html>

+ 0 - 15
public/manifest.json

@@ -1,15 +0,0 @@
-{
-  "short_name": "React App",
-  "name": "Create React App Sample",
-  "icons": [
-    {
-      "src": "favicon.ico",
-      "sizes": "64x64 32x32 24x24 16x16",
-      "type": "image/x-icon"
-    }
-  ],
-  "start_url": ".",
-  "display": "standalone",
-  "theme_color": "#000000",
-  "background_color": "#ffffff"
-}

+ 0 - 32
src/App.css

@@ -1,32 +0,0 @@
-.App {
-  text-align: center;
-}
-
-.App-logo {
-  animation: App-logo-spin infinite 20s linear;
-  height: 40vmin;
-}
-
-.App-header {
-  background-color: #282c34;
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-  align-items: center;
-  justify-content: center;
-  font-size: calc(10px + 2vmin);
-  color: white;
-}
-
-.App-link {
-  color: #61dafb;
-}
-
-@keyframes App-logo-spin {
-  from {
-    transform: rotate(0deg);
-  }
-  to {
-    transform: rotate(360deg);
-  }
-}

+ 0 - 28
src/App.js

@@ -1,28 +0,0 @@
-import React, { Component } from 'react';
-import logo from './logo.svg';
-import './App.css';
-
-class App extends Component {
-  render() {
-    return (
-      <div className="App">
-        <header className="App-header">
-          <img src={logo} className="App-logo" alt="logo" />
-          <p>
-            Edit <code>src/App.js</code> and save to reload.
-          </p>
-          <a
-            className="App-link"
-            href="https://reactjs.org"
-            target="_blank"
-            rel="noopener noreferrer"
-          >
-            Learn React
-          </a>
-        </header>
-      </div>
-    );
-  }
-}
-
-export default App;

+ 0 - 9
src/App.test.js

@@ -1,9 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-
-it('renders without crashing', () => {
-  const div = document.createElement('div');
-  ReactDOM.render(<App />, div);
-  ReactDOM.unmountComponentAtNode(div);
-});

+ 48 - 0
src/components/common/protectedRoute.js

@@ -0,0 +1,48 @@
+import React from 'react';
+import { Route, Redirect } from 'react-router-dom';
+import * as routes from './../../constants/routes';
+
+export default ({ component: Component, user: { data : checkedData }, tokenAuth, access, ...rest }) => (
+    <Route
+        {...rest}
+        render={props => {
+            {/* let checkedData;
+
+            if (data) {
+                checkedData = data;
+            }
+            else {
+                const storagedUser = JSON.parse(localStorage.getItem(token));
+                if (storagedUser) {
+                    checkedData = storagedUser;
+                    tokenAuth(storagedUser);
+                }
+                else {
+                    checkedData = null;
+                }
+            } */}
+
+            console.log('Component', Component);
+            console.log('Access', access);
+            console.log('CheckedData', checkedData);
+
+            if (access === 'public') {
+                return <Component {...props} />
+            }
+
+            if ((access === 'user-only' || access === 'admin-only') && !checkedData) {
+                return <Redirect to={routes.SIGN_IN} />
+            }
+
+            if (access === 'user-only' && checkedData) {
+                return <Component {...props} />
+            }
+
+            if (access === 'admin-only' && checkedData.role) {
+                return <Component {...props} />
+            }
+
+            return null // permission denied
+        }}
+    />
+)

+ 6 - 0
src/components/common/spinner.js

@@ -0,0 +1,6 @@
+import React from 'react';
+
+export default props => (
+    // add props optionally
+    null
+)

+ 49 - 0
src/configs/routerConfig.js

@@ -0,0 +1,49 @@
+import React, { lazy } from 'react';
+import * as routes from './../constants/routes';
+
+export default [
+    {
+        path: routes.LANDING,
+        access: 'public',
+        component: () => <div>landing</div>
+    },
+    {
+        path: routes.SIGN_IN,
+        access: 'public',
+        component: () => <div>sign in</div>
+    },
+    {
+        path: routes.SIGN_UP,
+        access: 'public',
+        component: () => <div>sign up</div>
+    },
+    {
+        path: routes.HOME,
+        access: 'user-only',
+        component: () => <div>home</div>
+    },
+    {
+        path: routes.CATEGORIES,
+        access: 'user-only',
+        component: () => <div>categories</div>
+    },
+    {
+        path: routes.PROFILE,
+        access: 'user-only',
+        component: () => <div>profile</div>
+    },
+    {
+        path: routes.TESTS,
+        access: 'user-only',
+        component: () => <div>test</div>
+    },
+    {
+        path: routes.DELETE_USER,
+        access: 'admin-only',
+        component: () => <div>delete user</div>
+    },
+    {
+        access: 'public',
+        component: () => <div>404</div>
+    },
+]

+ 9 - 0
src/constants/auth.js

@@ -0,0 +1,9 @@
+export const SIGN_IN_URL = 'https://quiz.maxcrc.de/api/v1/user?';
+export const SIGN_IN_REQUEST = 'SIGN_IN_REQUEST';
+export const SIGN_IN_REQUEST_SUCCESS = 'SIGN_IN_REQUEST_SUCCESS';
+export const SIGN_IN_REQUEST_FAILURE = 'SIGN_IN_REQUEST_FAILURE';
+
+export const SIGN_UP_URL = 'https://quiz.maxcrc.de/api/v1/user';
+export const SIGN_UP_REQUEST = 'SIGN_UP_REQUEST';
+export const SIGN_UP_REQUEST_SUCCESS = 'SIGN_UP_REQUEST_SUCCESS';
+export const SIGN_UP_REQUEST_FAILURE = 'SIGN_UP_REQUEST_FAILURE';

+ 14 - 0
src/constants/routes.js

@@ -0,0 +1,14 @@
+// Be careful ! Check all dependencies in config/config.js,
+// otherwise it may cause mistakes in router.js! 
+
+export const LANDING = '/';
+export const SIGN_UP = '/sign-up';
+export const SIGN_IN = '/sign-in';
+export const HOME = '/home';
+export const CREATE_CATEGORY = '/create-category';
+export const CATEGORIES = '/categories';
+export const PROFILE = '/profile';
+export const CREATE_TEST = '/create-test';
+export const DELETE_USER = '/delete-user'
+export const TESTS = '/test';
+export const PASSWORD_FORGET = '/pw-forget';

+ 0 - 14
src/index.css

@@ -1,14 +0,0 @@
-body {
-  margin: 0;
-  padding: 0;
-  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
-    "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
-    sans-serif;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-code {
-  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
-    monospace;
-}

+ 11 - 6
src/index.js

@@ -1,12 +1,17 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-import './index.css';
-import App from './App';
 import * as serviceWorker from './serviceWorker';
+import { Provider } from "react-redux";
+import { BrowserRouter } from "react-router-dom"
+import Router from './router'
+import reduxStore from './state'
 
-ReactDOM.render(<App />, document.getElementById('root'));
+ReactDOM.render(
+    <BrowserRouter>
+        <Provider store={reduxStore}>
+            <Router />
+        </Provider>
+    </BrowserRouter>,
+    document.getElementById('root'));
 
-// If you want your app to work offline and load faster, you can change
-// unregister() to register() below. Note this comes with some pitfalls.
-// Learn more about service workers: http://bit.ly/CRA-PWA
 serviceWorker.unregister();

File diff suppressed because it is too large
+ 0 - 7
src/logo.svg


+ 17 - 0
src/reducers/auth/signIn.js

@@ -0,0 +1,17 @@
+// import * as types from '';
+import intialState from './../initialState'
+import initialState from './../initialState';
+
+export default function signInReducer(state = initialState.signIn, {type, payload, error}) {
+    switch(type) {
+        case 1: {
+            return {
+                ...state,
+                test: 'test'
+            }
+        }
+        default: {
+            return state;
+        }
+    }
+}

+ 6 - 0
src/reducers/index.js

@@ -0,0 +1,6 @@
+import { combineReducers } from 'redux'
+import signIn from './auth/signIn'
+
+export default combineReducers({
+    signIn
+})

+ 3 - 0
src/reducers/initialState.js

@@ -0,0 +1,3 @@
+export default {
+    signIn: {}
+}

+ 52 - 0
src/router.js

@@ -0,0 +1,52 @@
+import React, { Suspense, lazy } from "react";
+import { Switch, Route, withRouter } from "react-router-dom";
+import { connect } from 'react-redux';
+
+// import Header from "./containers/header";
+// import Footer from './components/public-components/footer';
+
+import ProtectedRoute from './components/common/protectedRoute';
+import config from './configs/routerConfig';
+
+import { bindActionCreators } from "redux";
+
+class Router extends React.Component {
+    render() {
+        const { user, tokenAuth } = this.props;
+
+        // TODO: add spinner, user
+        return (
+            <div className="app">
+                <Suspense fallback={
+                    <div class="text-center">
+                        <div class="spinner-border" role="status">
+                            <span class="sr-only">Loading...</span>
+                        </div>
+                    </div>
+                }>
+                    <Switch>
+                        {config.map(route =>
+                            <ProtectedRoute
+                                path={route.path}
+                                component={route.component}
+                                access={route.access}
+                                user={{data: {role: 1}}}
+                                key={route}
+                                exact
+                            />
+                        )}
+                    </Switch>
+                </Suspense>
+            </div>
+        )
+    }
+}
+
+// const mapStateToProps = state => ({
+//     user: state.user
+// })
+// const mapDispatchToProps = dispatch => bindActionCreators({ tokenAuth }, dispatch);
+
+// export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Router));
+
+export default Router;

+ 10 - 0
src/sagas/auth/index.js

@@ -0,0 +1,10 @@
+import signIn from './signIn';
+import signUp from './signUp';
+import * as actionTypes from './../../constants/auth'
+
+import { takeEvery } from 'redux-saga/effects';
+
+export default function* () {
+    takeEvery(actionTypes.SIGN_IN_REQUEST, signIn)
+    takeEvery(actionTypes.SIGN_UP_REQUEST, signUp)
+}

+ 3 - 0
src/sagas/auth/signIn.js

@@ -0,0 +1,3 @@
+export default function* () {
+    
+}

+ 3 - 0
src/sagas/auth/signUp.js

@@ -0,0 +1,3 @@
+export default function* () {
+    
+}

+ 8 - 0
src/sagas/index.js

@@ -0,0 +1,8 @@
+import { fork } from "redux-saga/effects";
+import auth from './auth'
+
+export default function*() {
+    yield [
+        fork(auth)
+    ]
+}

+ 21 - 0
src/state/index.js

@@ -0,0 +1,21 @@
+import { createStore, applyMiddleware } from 'redux';
+import { createLogger } from 'redux-logger'
+import createSagaMiddleware from "redux-saga";
+
+import combinedReducers from './../reducers';
+import initialState from './../reducers/initialState'
+import sagas from './../sagas'
+
+const sagaMiddleware = createSagaMiddleware();
+const logger = createLogger({
+    predicate: (getState, action) => !action.type.includes('@@redux-form')
+});
+
+const store = createStore(
+    combinedReducers,
+    initialState,
+    applyMiddleware(sagaMiddleware, logger)
+);
+export default store;
+
+sagaMiddleware.run(sagas);