Svetlana hace 6 años
padre
commit
c64d760067
Se han modificado 70 ficheros con 4272 adiciones y 1971 borrados
  1. 1 0
      debug.log
  2. 2752 1662
      package-lock.json
  3. 3 2
      package.json
  4. 1 0
      public/index.html
  5. 5 1
      src/actions/auth/index.js
  6. 3 11
      src/actions/auth/signIn/index.js
  7. 7 0
      src/actions/auth/signOut/index.js
  8. 3 2
      src/actions/auth/signUp/index.js
  9. 6 0
      src/actions/auth/tokenAuth/index.js
  10. 18 0
      src/actions/auth/users/users.js
  11. 4 2
      src/actions/index.js
  12. 8 0
      src/components/common/formInput/index.js
  13. 48 0
      src/components/common/protectedRoute/config.js
  14. 34 0
      src/components/common/protectedRoute/index.js
  15. 15 0
      src/components/common/spinner/index.js
  16. 39 0
      src/components/public-components/auth/signInForm/index.js
  17. 16 0
      src/components/public-components/auth/signInForm/validate/index.js
  18. 39 0
      src/components/public-components/auth/signUpForm/index.js
  19. 42 0
      src/components/public-components/auth/signUpForm/validate/index.js
  20. 13 0
      src/components/public-components/footer/index.js
  21. 105 0
      src/components/public-components/header/index.js
  22. 28 0
      src/components/public-components/landingPage/index.js
  23. 12 0
      src/components/public-components/notFound/index.js
  24. 13 0
      src/components/public-components/permissionDenied/index.js
  25. 48 0
      src/components/user-components/admin-components/createTestForm/index.js
  26. 6 0
      src/components/user-components/admin-components/createTestForm/validate/index.js
  27. 49 0
      src/components/user-components/categoriesPage/index.js
  28. 7 0
      src/components/user-components/homePage/index.js
  29. 89 0
      src/components/user-components/profilePage/index.js
  30. 10 6
      src/constants/index.js
  31. 14 0
      src/constants/routes.js
  32. 35 0
      src/containers/auth/SignInPage/index.js
  33. 35 0
      src/containers/auth/SignUpPage/index.js
  34. 26 53
      src/containers/header/index.js
  35. 0 20
      src/firebase_config.js
  36. 0 14
      src/index.css
  37. 1 1
      src/index.js
  38. 0 42
      src/reducers/auth/signIn/index.js
  39. 0 30
      src/reducers/auth/signUp/index.js
  40. 7 7
      src/reducers/index.js
  41. 7 9
      src/reducers/initialState/index.js
  42. 86 0
      src/reducers/user/index.js
  43. 63 18
      src/router.js
  44. 2 0
      src/saga/auth/index.js
  45. 11 11
      src/saga/auth/signIn/index.js
  46. 9 2
      src/saga/auth/signUp/index.js
  47. 20 0
      src/saga/auth/users/users.js
  48. 0 16
      src/saga/category/category-card/category-cards.js
  49. 0 9
      src/saga/category/index.js
  50. 2 2
      src/saga/index.js
  51. 4 12
      src/state/index.js
  52. 9 8
      src/styles/abstracts/_variables.scss
  53. 38 3
      src/styles/base/_base.scss
  54. 3 0
      src/styles/base/_typography.scss
  55. 39 0
      src/styles/components/_button.scss
  56. 31 0
      src/styles/components/_categoriesPage.scss
  57. 5 0
      src/styles/components/_container.scss
  58. 0 0
      src/styles/components/_createTestPage.scss
  59. 23 0
      src/styles/components/_footer.scss
  60. 152 27
      src/styles/components/_header.scss
  61. 64 0
      src/styles/components/_landingPage.scss
  62. 24 0
      src/styles/components/_notFound.scss
  63. 16 0
      src/styles/components/_page.scss
  64. 30 0
      src/styles/components/_profilePage.scss
  65. 62 0
      src/styles/components/_signPage.scss
  66. 7 0
      src/styles/components/_spinner.scss
  67. 15 1
      src/styles/index.scss
  68. 1 0
      src/utils/token.js
  69. 6 0
      грабли.txt
  70. 1 0
      костыли.txt

+ 1 - 0
debug.log

@@ -0,0 +1 @@
+[0109/234712.714:ERROR:settings.cc(319)] Settings magic is not 1129342067

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 2752 - 1662
package-lock.json


+ 3 - 2
package.json

@@ -3,17 +3,18 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
-    "antd": "^3.11.2",
+    "axios": "^0.18.0",
     "bootstrap": "^4.1.3",
     "firebase": "^5.7.0",
     "node-sass": "^4.11.0",
     "normalize.css": "^8.0.1",
+    "prop-types": "^15.6.2",
     "react": "^16.6.3",
     "react-dom": "^16.6.3",
     "react-loader-spinner": "^2.3.0",
     "react-redux": "^6.0.0",
     "react-router-dom": "^4.3.1",
-    "react-scripts": "2.1.1",
+    "react-scripts": "^2.1.3",
     "redux": "^4.0.1",
     "redux-form": "^8.0.4",
     "redux-logger": "^3.0.6",

+ 1 - 0
public/index.html

@@ -6,6 +6,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
     <meta name="theme-color" content="#000000">
     <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
+    <!-- Fonts -->
     <title>React App</title>
   </head>
   <body>

+ 5 - 1
src/actions/auth/index.js

@@ -1,7 +1,11 @@
 import * as signInActions from './signIn';
 import * as signUpActions from './signUp';
+import * as signOutActions from './signOut';
+import * as usersGetActions from './signOut';
 
 export default {
     ...signInActions,
-    ...signUpActions
+    ...signUpActions,
+    ...signOutActions,
+    ...usersGetActions
 }

+ 3 - 11
src/actions/auth/signIn/index.js

@@ -2,8 +2,9 @@ import * as types from '../../../constants';
 
 // all actions for signing in
 
-export const signInRequest = () => ({
-    type: types.SIGN_IN_REQUEST
+export const signInRequest = payload => ({
+    type: types.SIGN_IN_REQUEST,
+    payload
 })
 
 export const signInRequestSucces = payload => ({
@@ -14,14 +15,5 @@ export const signInRequestSucces = payload => ({
 export const signInRequestFailure = error => ({
     type: types.SIGN_IN_REQUEST_FAILURE,
     error
-})
-
-export const userIsSignedIn = (payload) => ({
-    type: types.USER_IS_SIGNED_IN,
-    payload
-})
 
-export const userIsNotSignedIn = (payload) => ({
-    type: types.USER_IS_NOT_SIGNED_IN,
-    payload
 })

+ 7 - 0
src/actions/auth/signOut/index.js

@@ -0,0 +1,7 @@
+import * as types from '../../../constants';
+
+// all actions for signing out
+
+export const signOut = () => ({
+    type: types.SIGN_OUT
+})

+ 3 - 2
src/actions/auth/signUp/index.js

@@ -2,8 +2,9 @@ import * as types from '../../../constants';
 
 // all actions for signing up
 
-export const signUpRequest = () => ({
-    type: types.SIGN_UP_REQUEST
+export const signUpRequest = payload => ({
+    type: types.SIGN_UP_REQUEST,
+    payload
 })
 
 export const signUpRequestSucces = payload => ({

+ 6 - 0
src/actions/auth/tokenAuth/index.js

@@ -0,0 +1,6 @@
+import { TOKEN_AUTH } from './../../../constants';
+
+export const tokenAuth = (payload) => ({
+    type: TOKEN_AUTH,
+    payload
+})

+ 18 - 0
src/actions/auth/users/users.js

@@ -0,0 +1,18 @@
+import * as types from '../../../constants';
+
+// all actions for signing up
+
+export const usersGetRequest= payload => ({
+    type: types.USERS_GET_REQUEST,
+    payload
+})
+
+export const usersGetRequestSucces = payload => ({
+    type: types.USERS_GET_REQUEST_SUCCESS,
+    payload
+})
+
+export const usersGetRequestFailure = error => ({
+    type: types.USERS_GET_REQUEST_SUCCESS_FAILURE ,
+    error
+})

+ 4 - 2
src/actions/index.js

@@ -1,5 +1,7 @@
-import authActions from './auth/logIn';
-import categoryActions from './card/index'
+
+import authActions from './auth';
+
+
 export default {
     ...authActions,
     ...categoryActions

+ 8 - 0
src/components/common/formInput/index.js

@@ -0,0 +1,8 @@
+import React, { Fragment } from 'react';
+
+export default ({ input, className, placeholder, type, meta: { touched, error } }) => (
+    <Fragment>
+        <input className={className} placeholder={placeholder} type={type} {...input} />
+        {touched && (error && <p style={{"color": "red", "textTransform": "uppercase"}}>⚠ {error}</p>)}
+    </Fragment>
+)

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

@@ -0,0 +1,48 @@
+import * as routes from './../../../constants/routes';
+import { lazy } from 'react';
+
+const landingPage = lazy(() => import('./../../public-components/landingPage'));
+const homePage = lazy(() => import('./../../user-components/homePage'));
+const signInPage = lazy(() => import('./../../../containers/auth/SignInPage'));
+const signUpPage = lazy(() => import('./../../../containers/auth/SignUpPage'));
+const createTestForm = lazy(() => import('./../../user-components/admin-components/createTestForm'));
+const profilePage = lazy(() => import('./../../user-components/profilePage'));
+const categoriesPage = lazy(() => import('./../../user-components/categoriesPage'));
+
+export default [
+    {
+        path: routes.LANDING,
+        access: 'public',
+        component: landingPage
+    },
+    {
+        path: routes.SIGN_IN,
+        access: 'public',
+        component: signInPage
+    },
+    {
+        path: routes.SIGN_UP,
+        access: 'public',
+        component: signUpPage
+    },
+    {
+        path: routes.HOME,
+        access: 'user-only',
+        component: homePage
+    },
+    {
+        path: routes.CATEGORIES,
+        access: 'user-only',
+        component: categoriesPage
+    },
+    {
+        path: routes.PROFILE,
+        access: 'user-only',
+        component: profilePage
+    },
+    {
+        path: routes.CREATE_TEST,
+        access: 'admin-only',
+        component: createTestForm
+    }
+]

+ 34 - 0
src/components/common/protectedRoute/index.js

@@ -0,0 +1,34 @@
+import React from 'react';
+import { Route, Redirect } from 'react-router-dom';
+import config from './config';
+import * as routes from './../../../constants/routes';
+import PermissionDenied from './../../public-components/permissionDenied';
+
+export default ({ component: Component, user, access, ...rest  }) => (
+    <Route
+        {...rest}
+        render={props => {
+
+            if (access === 'public') {
+                return <Component {...props} />
+            }
+            
+            if ( (access === 'user-only' || access === 'admin-only') && !user.data ) {
+                return <Redirect to={routes.SIGN_IN}/>
+            }
+            
+            if (access === 'user-only' && user.data) {
+                return <Component {...props} />
+            }        
+
+            if (access === 'admin-only') {
+                if (user.isAdmin) {
+                    return <Component {...props} />
+                } 
+
+                return <PermissionDenied />
+            }
+            
+        }}
+    />
+)

+ 15 - 0
src/components/common/spinner/index.js

@@ -0,0 +1,15 @@
+import React from 'react';
+import Loader from 'react-loader-spinner'
+
+export default props => (
+    // add props optionally
+
+    <div className="spinner">
+        <Loader
+            type="ThreeDots"
+            color="lightgrey"
+            height="100"
+            width="100"
+        />
+    </div>
+)

+ 39 - 0
src/components/public-components/auth/signInForm/index.js

@@ -0,0 +1,39 @@
+import React from 'react';
+import { Field, reduxForm } from 'redux-form'
+
+import validate from './validate'
+import formInput from './../../../common/formInput'
+
+import { Link } from 'react-router-dom'
+import * as routes from './../../../../constants/routes'
+
+class Form extends React.Component {
+    sendRequest = values => {
+        const { actions: { signInRequest } } = this.props;
+        signInRequest(values);
+    }
+
+    render() {
+        const { invalid, handleSubmit, submitting } = this.props;
+
+        return (
+            <form className="sign-form" onSubmit={handleSubmit(this.sendRequest)}>
+                <h2 className="sign-form__header">Sign In</h2>
+
+                <Field className="sign-form__input sign-form__input--text" placeholder="Login" name="login" component={formInput} type="text" />
+                <Field className="sign-form__input sign-form__input--password" placeholder="Password" name="password" component={formInput} type="password" />
+                
+                <button className="link--btn link--btn60" disabled={invalid || submitting}>Sign In</button>
+                
+                <p className="sign-form__link--forgot-password"><Link className="link--inline" to={routes.PASSWORD_FORGET}>Forgot password ?</Link></p>
+                <hr className="sign-form__divider" />
+                <p className="sign-form__link--sign-up">Still ain't got an account? <Link className="link--inline" to={routes.SIGN_UP}>Sign up</Link> first!</p>
+            </form>
+        )
+    }
+}
+
+export default reduxForm({
+    form: "signIn",
+    validate
+})(Form)

+ 16 - 0
src/components/public-components/auth/signInForm/validate/index.js

@@ -0,0 +1,16 @@
+export default function validate(values) {
+    const { login, password } = values;
+    const errors = {};
+
+    // console.log("Validate, sign-in page form: ", values);
+
+    if (!login) {
+        errors.login = "Required";
+    }
+
+    if (!password) {
+        errors.password = "Required"
+    }
+
+    return errors;
+}

+ 39 - 0
src/components/public-components/auth/signUpForm/index.js

@@ -0,0 +1,39 @@
+import React from 'react';
+import { Field, reduxForm } from 'redux-form'
+import validate from './validate'
+import formInput from './../../../common/formInput'
+
+class Form extends React.Component {
+
+    sendRequest = values => {
+        const { actions: { signUpRequest } } = this.props;
+        delete values.passwordConfirmation;
+        signUpRequest(values);
+    }
+
+    render() {
+        const { invalid, handleSubmit } = this.props;
+
+        return (
+            <form className="sign-form" onSubmit={handleSubmit(this.sendRequest)}>
+
+                <h2 className="sign-form__header">Sign Up</h2>
+
+                <Field name="login" className="sign-form__input sign-form__input--text" placeholder="Login" component={formInput} type="text" />
+
+                <div className="sign-form__password-container">
+                    <Field name="password" className="sign-form__input sign-form__input--password" placeholder="Password" component={formInput} type="password" />
+                    <Field name="passwordConfirmation" className="sign-form__input sign-form__input--password" placeholder="Password confirmation" component={formInput} type="password" />
+                </div>
+
+                <button className="sign-form__link--with-margin link--btn link--btn6s0" disabled={invalid}>Create Account</button>
+                <p className="sign-form__agreement">By clicking this button you actually would donate us your flat !</p>
+            </form>
+        )
+    }
+}
+
+export default reduxForm({
+    form: "signUp",
+    validate
+})(Form)

+ 42 - 0
src/components/public-components/auth/signUpForm/validate/index.js

@@ -0,0 +1,42 @@
+export default function validate(values) {
+    const { login, password, passwordConfirmation } = values;
+    const errors = {};
+
+    if (!login) {
+        errors.login = "Required";
+    }
+    else if (/[,]/.test(login)) {
+        errors.login = "Invalid symbol: \",\" is not allowed!";
+    }
+    else if (login.length < 8 || login.length > 20) {
+        errors.login = "Invalid login length: login should be from 8 to 20 symbols";
+    }
+    else if (
+        !/^(([^<>()\]\\.,;:\s@"]+(\.[^<>()\]\\.,;:\s@"]+)*)|(".+"))@(([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(login)) {
+        errors.login = "Invalid login, try another one";
+    }
+    
+    if (!password) {
+        errors.password = "Required"
+    }
+    else if (/[,]/.test(password)) {
+        errors.password = "Invalid symbol: \",\" is not allowed!";
+    }
+    else if (password.length < 8 || password.length > 20) {
+        errors.password = "Invalid password length: password should be from 8 to 20 symbols";
+    }
+    else if (!/^[a-z0-9_-]{8,20}$/i.test(password)) {
+        errors.password = "Invalid password, try another one";
+    }
+
+    if (!passwordConfirmation) {
+        errors.passwordConfirmation = "Required";
+    }
+    else if (password !== passwordConfirmation) {
+        errors.passwordConfirmation = "Passwords don't match each other!";
+    }
+
+
+
+    return errors;
+}

+ 13 - 0
src/components/public-components/footer/index.js

@@ -0,0 +1,13 @@
+import React from 'react';
+import store from './../../../state';
+
+export default props => (
+    <div className="footer">
+        <p className="footer__us">
+            TOP-company
+            "<span className="footer__us us__inline--red">T</span>est.<span className="footer__us us__inline--green">i</span>o"
+        </p>
+        <p className="footer__copyright">&copy; 2018, 'Test.io', all right reserved</p>
+        <button style={{"z-index": 4000, "color": "red"}} onClick={() => console.log(store.getState())}>Redux - State</button>
+    </div>
+)

+ 105 - 0
src/components/public-components/header/index.js

@@ -0,0 +1,105 @@
+import React, { Component } from 'react';
+import { Link } from "react-router-dom";
+import * as routes from './../../../constants/routes';
+import { UserContext } from './../../../containers/header';
+
+export default class header extends Component {
+
+    state = {
+        togglerClosed: true,
+    }
+
+    handleToggle = (event) => {
+        this.setState((prevState) => ({ togglerClosed: !prevState.togglerClosed }))
+    }
+
+    render() {
+        const { togglerClosed } = this.state;
+        const toggleStatus = togglerClosed ? "toggle-status--closed" : "toggle-status--opened"
+
+        return (
+            <UserContext.Consumer>
+                {
+                    ({ user, signOut }) => (
+                        <header className="header">
+                            <Link to={routes.LANDING}>
+                                <h1 className="header__logo">Test.<span className="header__logo--i-letter">i</span>o</h1>
+                            </Link>
+                            <hr className="header__logo--divider" />
+                            <span className="header__toggle-trigger" onClick={this.handleToggle} >
+                                <span />
+                            </span>
+                            <div className="header__flex-wrapper">
+                                <nav className={`header__nav ${toggleStatus}`}>
+                                    <ul className="header__nav nav__list"  >
+                                        <li>
+                                            <Link className="header__nav nav__list-item" to={routes.HOME}>
+                                                Home
+                                            </Link>
+                                        </li>
+                                        <li>
+                                            <Link className="header__nav nav__list-item" to={routes.PROFILE}>
+                                                Profile
+                                            </Link>
+                                        </li>
+                                        <li>
+                                            <Link className="header__nav nav__list-item" to={routes.TESTS}>
+                                                Test
+                                            </Link>
+                                        </li>
+                                        <li>
+                                            <Link className="header__nav nav__list-item" to={routes.CATEGORIES}>
+                                                Categories
+                                            </Link>
+                                        </li>
+                                        {
+                                            user && user.isAdmin && (
+                                                <React.Fragment>
+                                                    <li>
+                                                        <Link className="header__nav nav__list-item--admin-only" to={routes.CREATE_TEST}>
+                                                            Create test
+                                                        </Link>
+                                                    </li>
+                                                    <li>
+                                                        <Link className="header__nav nav__list-item--admin-only" to={routes.CREATE_CATEGORY}>
+                                                            Create category
+                                                        </Link>
+                                                    </li>
+                                                    <li>
+                                                        <Link className="header__nav nav__list-item--admin-only" to={routes.DELETE_USER}>
+                                                            Delete user
+                                                        </Link>
+                                                    </li>
+                                                </React.Fragment>
+                                            )
+                                        }
+                                    </ul>
+                                </nav>
+
+                                <div className="header__links">
+                                    {
+                                        !user.data
+                                            ? (
+                                                <React.Fragment>
+                                                    <Link className="header__links--sign-in link--btn link--btn25" to={routes.SIGN_IN}>Sign in</Link>
+                                                    <Link className="header__links--sign-up link--btn link--btn25" to={routes.SIGN_UP}>Sign up</Link>
+                                                </React.Fragment>
+                                            )
+                                            : (
+                                                <button
+                                                    className="header__links--sign-in link--btn link--btn25"
+                                                    onClick={signOut}
+                                                >
+                                                    Sign out
+                                                </button>
+                                            )
+                                    }
+                                </div>
+                            </div>
+                        </header>
+                    )
+                }
+            </UserContext.Consumer>
+        )
+    }
+}

+ 28 - 0
src/components/public-components/landingPage/index.js

@@ -0,0 +1,28 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import * as routes from './../../../constants/routes'
+
+export default props => (
+    <div className="page landing-page">
+        <div className="container landing-page__about">
+            <h1 className="description__header">
+                We are the powerfull servise providing you the ability to create and manage
+                your own tests, in any categories, choosing your own marking methods.
+            </h1>
+            <hr className="description__divider" />
+            <p className="description__main">
+                You can <span className="description__inline--pretty">share</span>
+                {" "}your test with anybody you'd like: no matter your friend or college or even subordinates
+                can easily pass them, get marks and <span className="description__inline--pretty">share</span> ones!
+            </p>
+        </div>
+        <div className="container landing-page__links-container">
+            <Link to={routes.SIGN_IN} className="landing-page__links landing-page__links--sign-in">
+                Sign in
+            </Link>
+            <Link to={routes.SIGN_UP} className="landing-page__links landing-page__links--sign-up">
+                Sign up
+            </Link>
+        </div>
+    </div>
+)

+ 12 - 0
src/components/public-components/notFound/index.js

@@ -0,0 +1,12 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { HOME } from './../../../constants/routes'
+
+export default props => (
+    <div className="page not-found">
+        <img className="not-found__image" src="http://kiwanismiracleleague.org/wp-content/themes/chillibox/media/images/404.png" alt="404" />
+        <hr className="not-found__divider"/>
+        <h1 className="not-found__message">Sorry, but looks like nobody lives here...</h1>
+        <p><Link className="link--btn link--btn-big not-found__link--home" to={HOME}>Go home</Link></p>
+    </div>
+)

+ 13 - 0
src/components/public-components/permissionDenied/index.js

@@ -0,0 +1,13 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+
+
+export default () => (
+    <div className="page permission-denied-page">
+        <h1 className="permission-denied-page__header">
+            Sorry, but looks like u are not the admin...
+        </h1>
+        <p>Buy our superior premium pack to be able to create new tests!</p>
+        <Link className="">Buy!</Link>
+    </div>
+)

+ 48 - 0
src/components/user-components/admin-components/createTestForm/index.js

@@ -0,0 +1,48 @@
+import React from 'react';
+import { reduxForm, Field } from 'redux-form';
+import validate from './validate';
+import formInput from './../../../common/formInput'
+
+class Form extends React.Component {
+    sendRequest(values) {
+        console.log('sendRequest createTestForm page values:', values);
+    }
+
+    render() {
+        const { handleSubmit } = this.props;
+
+        return (
+            <form className="page" onSubmit={handleSubmit(this.sendRequest)}>
+                <h2>Make a title-page for your test!</h2>
+
+                <div className="title-page__block">
+                    <p className="titles">Title</p>
+                    <Field
+                        className="title-page__block"
+                        name="title"
+                        type="input"
+                        placeholder=""
+                        component={formInput}
+                    />
+                </div>
+
+                <div className="title-page__block">
+                    <p className="titles">Description</p>
+                    <Field name="description" type="input" placeholder="" className="" component={formInput} />
+                </div>
+
+                <div className="title-page__block">
+                    <p className="titles">Cover image</p>
+                    <Field name="cover" type="file" placeholder="" className="" component="textarea" />
+                </div>
+
+                <button className="">Create card</button>
+            </form>
+        )
+    }   
+}
+
+export default reduxForm({
+    form: "createTest",
+    validate
+})(Form)

+ 6 - 0
src/components/user-components/admin-components/createTestForm/validate/index.js

@@ -0,0 +1,6 @@
+export default function validate(values) {
+    const {} = values;
+    const errors = {}
+
+    return errors;
+}

+ 49 - 0
src/components/user-components/categoriesPage/index.js

@@ -0,0 +1,49 @@
+import React from 'react';
+import axios from 'axios';
+
+class categoriesPage extends React.Component {
+
+    state = {
+        categories: []
+    }
+
+    getCategories = () => {
+        axios.get('http://127.0.0.1:2000/api/categories')
+            .then(({ data }) => this.setState({
+                categories: data
+            }))
+            .catch(({ message }) => console.warn(message))
+    }
+
+    componentDidMount() {
+        this.getCategories()
+    }
+
+    render() {
+        const { categories } = this.state;
+        console.log("Categories - ", categories);
+
+        return ( 
+            <div className="page page--bottom-only categories-page">
+                <div className="container categories-grid">
+                    {categories.map(el => (
+                        <div
+                            className="categories-grid__element"
+                            style={{ background: `url("${el.cover}") no-repeat center center` }}
+                        >
+                            <a href={el.title}>
+                                <div className="container categories-grid__content-wrapper">
+                                    <h2>{el.title}</h2>
+                                    <hr className="divider" />
+                                    <p>{el.description}</p>
+                                </div>
+                            </a>
+                        </div>
+                    ))}
+                </div>
+            </div>
+        )
+    }
+}
+
+export default categoriesPage;

+ 7 - 0
src/components/user-components/homePage/index.js

@@ -0,0 +1,7 @@
+import React from 'react';
+
+export default props => (
+    <div className="page">
+        There should be a home component
+    </div>
+)

+ 89 - 0
src/components/user-components/profilePage/index.js

@@ -0,0 +1,89 @@
+import React from 'react';
+import { connect } from 'react-redux';
+// import { bindActionCreators } from 'redux'
+// import {} from './../../../actions'
+import axios from 'axios';
+
+// redux-connected container
+
+class profilePage extends React.Component {
+
+    state = {
+        user: {}
+    }
+
+    getUser = () => {
+        const randomUserId = Math.ceil(Math.random() * 10);
+
+        axios.post(`https://quiz.maxcrc.de/api/v1/user`,{
+            "login": 'ddd',
+            "password":"jhgfhgg"
+
+        })
+            .then(({ data }) => this.setState({
+                user: data
+            }))
+            .catch(({ message }) => console.warn(message))
+    }
+
+    componentDidMount() {
+        this.getUser();
+    }
+
+    render() {
+        const { user } = this.state;
+
+        console.log(user);
+
+        return (
+            <div className="page page--bottom-only profile-page">
+                <section className="container section section--about">
+                    <h2 className="section__element section__element--header">{user.login}</h2>
+                    <img className="section__element section__element--image" src={user.avatar} alt="avatar" />
+                    <div className="sedtion__element section__element--login">
+                        <h3>Login</h3>
+                        <p>{user.login}<button className="link link--btn right">Change login</button></p>
+                    </div>
+                    <div className="section__element section__element--">
+                        <h3>E-mail</h3>
+                        <p>{user.email}<button className="link link--btn right">Change e-mail</button></p>
+                    </div>
+                    <div className="section__element section__element--">
+                        <h3>Status</h3>
+                        <p>{user.description}</p>
+                    </div>
+                </section>
+                <section className="container section section--stats">
+                    <div className="section__element section__element--">
+                        <h3>Member Since</h3>
+                        <p>{new Date(user.createdAt).toLocaleString()}</p>
+                    </div>
+                    <div className="section__element section__element--comments">
+                        <h3>Last comments</h3>
+                        <p className="comments-block">
+                            {
+                                user.comments && user.comments
+                                    .slice(0, 60)
+                                    .map(el =>
+                                        <p>
+                                            <h4>{new Date(el.createdAt).toLocaleString()}</h4>
+                                            {el.text}
+                                        </p>)
+                            }
+                        </p>
+                    </div>
+                </section>
+            </div>
+        )
+    }
+
+}
+
+const
+    mapStateToProps = state => ({
+        user: state.user
+    })
+// mapDispatchToProps = dispatch => bindActionCreators({}, dispatch)
+
+export default connect(mapStateToProps)(profilePage);
+

+ 10 - 6
src/constants/index.js

@@ -1,9 +1,9 @@
-export const SIGN_IN_URL = 'https://projectbasetest.firebaseio.com/users.json';
+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://projectbasetest.firebaseio.com/users.json';
+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';
@@ -11,7 +11,11 @@ export const SIGN_UP_REQUEST_FAILURE = 'SIGN_UP_REQUEST_FAILURE';
 export const USER_IS_SIGNED_IN = 'USER_IS_SIGNED_IN';
 export const USER_IS_NOT_SIGNED_IN = 'USER_IS_NOT_SIGNED_IN';
 
-export const CATEGORY_URL ='https://projectbasetest.firebaseio.com/category.json';
-export const CATEGORY_URL_REQUEST = 'CATEGORY_URL_REQUEST';
-export const CATEGORY_URL_REQUEST_SUCCESS = 'CATEGORY_URL_REQUEST_SUCCESS';
-export const CATEGORY_URL_REQUEST_FAILURE = 'CATEGORY_URL_REQUEST_FAILURE';
+export const SIGN_OUT = 'SIGN_OUT';
+
+export const USERS_GET_REQUEST = 'USERS_GET_REQUEST';
+export const USERS_GET_REQUEST_SUCCESS = 'USERS_GET_REQUEST_SUCCESS';
+export const USERS_GET_REQUEST_SUCCESS_FAILURE = 'USERS_GET_REQUEST_FAILURE';
+
+export const TOKEN_AUTH = 'TOKEN_AUTH';
+

+ 14 - 0
src/constants/routes.js

@@ -0,0 +1,14 @@
+// Be careful ! Check all dependencies in protectedRoute/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';

+ 35 - 0
src/containers/auth/SignInPage/index.js

@@ -0,0 +1,35 @@
+import React from 'react';
+import { signInRequest } from './../../../actions/auth/signIn'
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+
+import { Redirect } from 'react-router';
+import { HOME } from './../../../constants/routes';
+
+import SignInForm from './../../../components/public-components/auth/signInForm'
+
+class SignInPage extends React.Component {
+
+    render() {
+        const { signInRequest, user } = this.props;
+        return (
+            !(user.data)
+                ? (
+                    <div className="page sign-in">
+                        <SignInForm actions={{ signInRequest }} />
+                    </div>
+                )
+                : (
+                    <Redirect to={HOME} />
+                )
+        )
+    }
+}
+
+const
+    mapStateToProps = ({ user }) => ({
+        user
+    }),
+    mapDispatchToProps = dispatch => bindActionCreators({ signInRequest }, dispatch)
+
+export default connect(mapStateToProps, mapDispatchToProps)(SignInPage)

+ 35 - 0
src/containers/auth/SignUpPage/index.js

@@ -0,0 +1,35 @@
+import React from 'react';
+import { signUpRequest } from './../../../actions/auth/signUp';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+
+import { Redirect } from 'react-router'
+import { HOME } from './../../../constants/routes';
+
+import SignUpForm from './../../../components/public-components/auth/signUpForm';
+
+class SignUpPage extends React.Component {
+
+    render() {
+        const { signUpRequest, user } = this.props;
+        return (
+            !(user.data)
+                ? (
+                    <div className="page sign-up">
+                        <SignUpForm actions={{ signUpRequest }} />
+                    </div>
+                )
+                : (
+                    <Redirect to={HOME} />
+                )
+        )
+    }
+}
+
+const
+    mapStateToProps = ({ user }) => ({
+        user
+    }),
+    mapDispatchToProps = dispatch => bindActionCreators({ signUpRequest }, dispatch)
+
+export default connect(mapStateToProps, mapDispatchToProps)(SignUpPage)

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 26 - 53
src/containers/header/index.js


+ 0 - 20
src/firebase_config.js

@@ -1,20 +0,0 @@
-import firebase from "firebase"
-
-// Initialize Firebase
-var config = {
-    apiKey: "AIzaSyBtE3XNH2Hbj-2LiGrmNOGLcxVC-YbmIqU",
-    authDomain: "projectbasetest.firebaseapp.com",
-    databaseURL: "https://projectbasetest.firebaseio.com",
-    projectId: "projectbasetest",
-    storageBucket: "projectbasetest.appspot.com",
-    messagingSenderId: "706084402090"
-};
-
-firebase.initializeApp(config);
-
-export const database = firebase.database();
-export const storage = firebase.storage();
-export const auth = firebase.auth();
-export const googleAuthProvider = new firebase.auth.GoogleAuthProvider()
-
-export default firebase;

+ 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;
-}

+ 1 - 1
src/index.js

@@ -17,4 +17,4 @@ ReactDOM.render(
 	document.getElementById("root")
 );
 
-serviceWorker.unregister();
+serviceWorker.unregister();

+ 0 - 42
src/reducers/auth/signIn/index.js

@@ -1,42 +0,0 @@
-import * as types from "../../../constants";
-import initialState from './../../initialState';
-
-export default function signIn(state = initialState.signIn, {type, payload: user, error}) {
-    switch (type) {
-        case types.SIGN_IN_REQUEST: {
-            return {
-                ...state,
-                isFetching: true
-            }
-        }
-        case types.SIGN_IN_REQUEST_SUCCESS: {
-            return {
-                ...state,
-                user,
-                isFetching: false
-            }
-        }
-        case types.SIGN_IN_REQUEST_FAILURE: {
-            return {
-                ...state,
-                error,
-                isFetching: false
-            }
-        }
-        case types.USER_IS_SIGNED_IN: {
-            return {
-                ...state,
-                user
-            }
-        }
-        case types.USER_IS_NOT_SIGNED_IN: {
-            return {
-                ...state,
-                user: null
-            }
-        }
-        default: {
-            return state
-        }
-    }
-}

+ 0 - 30
src/reducers/auth/signUp/index.js

@@ -1,30 +0,0 @@
-import * as types from "../../../constants";
-import initialState from './../../initialState'
-
-export default function signUp(state = initialState.signUp, {type, payload, error}) {
-    switch (type) {
-        case types.SIGN_UP_REQUEST: {
-            return {
-                ...state,
-                isFetching: true
-            }
-        }
-        case types.SIGN_UP_REQUEST_SUCCESS: {
-            return {
-                ...state,
-                payload,
-                isFetching: false
-            }
-        }
-        case types.SIGN_UP_REQUEST_FAILURE: {
-            return {
-                ...state,
-                error,
-                isFetching: false
-            }
-        }
-        default: {
-            return state
-        }
-    }
-}

+ 7 - 7
src/reducers/index.js

@@ -1,14 +1,14 @@
 // Сюда добавляем редьюсеров для combineReducers и импортируем их в state,
 // для создания store 
-
 import { combineReducers } from 'redux';
-import signIn from './auth/signIn';
-import signUp from './auth/signUp';
-import cardS from './card-category/reduser-card'
+
+
+import user from './user';
+import { reducer as form } from 'redux-form';
+
 const combinedReducers = combineReducers({
-    signIn,
-    signUp,
-    
+    form,
+    user
 })
 
 export default combinedReducers;

+ 7 - 9
src/reducers/initialState/index.js

@@ -1,11 +1,9 @@
 export default {
-    signIn: {
-        isFetching: false,
-        user: null,
-     
-    },
-    signUp: {},
-    card:{
-        category:null
-       }
+    user: {
+        
+        data: null,
+        error: null,
+        gettingUser: null,
+        isAdmin: null
+    }
 }

+ 86 - 0
src/reducers/user/index.js

@@ -0,0 +1,86 @@
+import initialState from './../initialState';
+import * as types from './../../constants';
+
+export default function (state = initialState.user, { type, error, payload: data }) {
+    switch(type) {
+
+        case types.TOKEN_AUTH: {
+            return {
+                ...state,
+                data
+            }
+        }
+
+        // SIGN_UP
+
+        case types.SIGN_UP_REQUEST: {
+            return {
+                ...state,
+                gettingUser: true,
+                error: null,
+                data: null
+            }
+        }
+        case types.SIGN_UP_REQUEST_SUCCESS: {
+            return {
+                ...state,
+                gettingUser: false,
+                error: null,
+                data
+            }
+        }
+        case types.SIGN_UP_REQUEST_FAILURE: {
+            return {
+                ...state,
+                gettingUser: false,
+                data: null,
+                error
+            }
+        }
+
+        // SIGN_IN
+
+        case types.SIGN_IN_REQUEST: {
+            return {
+                ...state,
+                gettingUser: true,
+                error: null,
+                data: null
+            }
+        }
+        case types.SIGN_IN_REQUEST_SUCCESS: {
+            return {
+                ...state,
+                gettingUser: false,
+                error: null,
+                data                
+            }
+        }
+        case types.SIGN_IN_REQUEST_FAILURE: {
+            return {
+                ...state,
+                gettingUser: false,
+                data: null,
+                error
+            }
+        }
+
+        // SIGN_OUT
+
+        case types.SIGN_OUT: {
+            return initialState.user
+        }
+
+        // DEFAULT
+
+        default: {
+            return {...state}
+            
+        }
+    }
+}
+
+
+
+
+

+ 63 - 18
src/router.js

@@ -1,19 +1,64 @@
-import React from "react";
-import { Switch, Route } from "react-router-dom";
-import AuthPage from './containers/AuthPage';
+
+import React, { Suspense, lazy } from "react";
+import { Switch, Route, withRouter } from "react-router-dom";
+import { connect } from 'react-redux';
+import { tokenAuth } from './actions/auth/tokenAuth'
+
 import Header from "./containers/header";
-import AddCard from "./containers/new-card/add-card";
-
-
-export default () => (
-	<div className="container">
-		<Header />
-		<Switch>
-            <Route path="/" exact component={AuthPage} />
-		<Route path="/favorites" exact component={AuthPage} />
-		<Route path="/add" exact component={AddCard} />
-		<Route path="/passed" exact component={AuthPage} />
-		<Route path="/results" exact component={AuthPage} />
-		</Switch>
-	</div>
-);
+import Footer from './components/public-components/footer';
+
+import Spinner from "./components/common/spinner";
+
+import ProtectedRoute from './components/common/protectedRoute';
+import config from './components/common/protectedRoute/config';
+
+import fakeToken from './utils/token'
+import { bindActionCreators } from "redux";
+
+const notFound = lazy(() => import('./components/public-components/notFound'));
+
+class Router extends React.Component {
+
+    componentDidMount() {
+        const storagedUser = localStorage.getItem(fakeToken);
+        const { tokenAuth } = this.props;
+
+        storagedUser && tokenAuth(storagedUser);
+    }
+
+    render() {
+        const { user } = this.props;
+
+        //map located here because of switch-bag
+
+        const protectedRoutes = config.map(route =>
+            <ProtectedRoute
+                path={route.path}
+                component={route.component}
+                access={route.access}
+                user={user}
+                exact
+            />
+        );
+
+        return (
+            <div className="app">
+                <Header />
+                <Suspense fallback={<Spinner />}>
+                    <Switch>
+                        {protectedRoutes}
+                        <Route component={notFound} />
+                    </Switch>
+                </Suspense>
+                <Footer />
+            </div>
+        )
+    }
+}
+
+const mapStateToProps = state => ({
+    user: state.user
+})
+const mapDispatchToProps = dispatch => bindActionCreators({ tokenAuth }, dispatch);
+
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Router));

+ 2 - 0
src/saga/auth/index.js

@@ -3,10 +3,12 @@ import * as types from "./../../constants"
 
 import signIn from './signIn';
 import signUp from './signUp';
+import getUsers from './users/users';
 
 export default function*() {
     yield takeEvery(types.SIGN_IN_REQUEST, signIn);
     yield takeEvery(types.SIGN_UP_REQUEST, signUp);
+    yield takeEvery(types.USERS_GET_REQUEST, getUsers);
 }
 
 

+ 11 - 11
src/saga/auth/signIn/index.js

@@ -1,21 +1,21 @@
 import { put, call } from "redux-saga/effects";
 import * as actions from './../../../actions/auth/signIn'
-import { auth, googleAuthProvider } from './../../../firebase_config'
+import axios from 'axios';
+
 
 // worker-saga for signing in
 
-export default function* () {
+export default function* ({ payload: requestBody }) {
     try {
-        const payload = yield call(() => {
-            return (
-                auth.signInWithPopup(googleAuthProvider)
-                    .then(res => res.user)
-            )
-        });
-        console.log("Payload", payload);
+        // console.log('received request body from sign-in worker saga', requestBody);
+        const payload = yield call(() =>
+            axios.post(`https://quiz.maxcrc.de/api/v1/user`, {...requestBody})
+                .then(({ data }) => data)
+        );
+        // console.log("Payload", payload);
         yield put(actions.signInRequestSucces(payload));
     }
-    catch (exception) {
-        yield put(actions.signInRequestFailure(exception.message))
+    catch ({ message }) {
+        yield put(actions.signInRequestFailure(message))
     }
 }

+ 9 - 2
src/saga/auth/signUp/index.js

@@ -1,13 +1,20 @@
 import { put, call } from "redux-saga/effects";
 import * as actions from './../../../actions/auth/signUp'
+import axios from 'axios';
 
 import { SIGN_UP_URL } from '../../../constants'
 
 // worker-saga for signing up
 
-export default function* () {
+export default function* ({ payload: requestBody }) {
     try {
-        const payload = yield call( () => fetch(SIGN_UP_URL).then(res => res.json()) );
+        const payload = yield call(() => 
+        axios.post(`https://quiz.maxcrc.de/api/v1/user`, {
+            ...requestBody
+        })
+            .then(({ data }) => data)
+
+    );
         yield put(actions.signUpRequestSucces(payload));
     }
     catch (exception) {

+ 20 - 0
src/saga/auth/users/users.js

@@ -0,0 +1,20 @@
+import { put, call } from "redux-saga/effects";
+import * as actions from './../../../actions/auth/users/users'
+import axios from 'axios';
+
+
+
+export default function* ({ payload: requestBody }) {
+    try {
+        // console.log('received request body from sign-in worker saga', requestBody);
+        const payload = yield call(() =>
+            axios.get(`https://quiz.maxcrc.de/api/v1/user`)
+                .then(({ data }) => data)
+        );
+        // console.log("Payload", payload);
+        yield put(actions.usersGetRequestSucces(payload));
+    }
+    catch ({ message }) {
+        yield put(actions.usersGetRequestFailure(message))
+    }
+}

+ 0 - 16
src/saga/category/category-card/category-cards.js

@@ -1,16 +0,0 @@
-import { put, call } from "redux-saga/effects";
-import * as actions from '../../../actions/card/action-card'
-
-import { CATEGORY_URL } from '../../../constants'
-
-// worker-saga for signing up
-
-export default function* () {
-    try {
-        const payload = yield call( () => fetch(CATEGORY_URL).then(res => res.json()) );
-        yield put(actions.categoryRequestSucces (payload));
-    }
-    catch (exception) {
-        yield put(actions.categoryRequestFailure(exception.message))
-    }
-}

+ 0 - 9
src/saga/category/index.js

@@ -1,9 +0,0 @@
-import { takeEvery } from "redux-saga/effects";
-import * as types from "./../../constants"
-
-import categoryCard from "./category-card/category-cards"
-
-export default function*() {
-    yield takeEvery(types.CATEGORY_URL_REQUEST, categoryCard)
-
-}

+ 2 - 2
src/saga/index.js

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

+ 4 - 12
src/state/index.js

@@ -1,29 +1,21 @@
 import { createStore, applyMiddleware } from 'redux';
-import { logger } from 'redux-logger'
+import { createLogger } from 'redux-logger'
 import createSagaMiddleware from "redux-saga";
 
 import combinedReducers from './../reducers';
 import initialState from './../reducers/initialState'
 import saga from './../saga'
-import { auth } from './../firebase_config'
-import { userIsNotSignedIn, userIsSignedIn } from './../actions/auth/signIn'
 
 const sagaMiddleware = createSagaMiddleware();
+const logger = createLogger({
+    predicate: (getState, action) => !action.type.includes('@@redux-form')
+});
 
 const store = createStore(
     combinedReducers,
     initialState,
     applyMiddleware(sagaMiddleware)
 );
-
-// action
-auth.onAuthStateChanged(user => user
-    ? store.dispatch(userIsSignedIn(user)) 
-    : store.dispatch(userIsNotSignedIn())
-);
-
-
-
 export default store;
 
 sagaMiddleware.run(saga);

+ 9 - 8
src/styles/abstracts/_variables.scss

@@ -2,17 +2,18 @@ $color-white: #fff;
 $color-red: #f00;
 $color-red-dark: #b40000;
 $color-yellow: #f5a623;
-$color-green: #0ea500;
+$color-green: #008000;
 $color-blue: #008ff7;
 $color-blue-light-dark: #4a90e2;
 $color-blue-dark: #29336f;
 $color-blue-light: #eaf1f9;
 $color-brown: #4c4c4c;
-$color-grey: #51606a;
-$color-grey-light: #999999;
-$color-grey-lighter: #d8d8d8;
-$color-grey-the-lightest: #f9fbfd;
-$color-grey-transparent: rgba(247, 249, 251, 0.7);
-$color_lightsteelblue: #B0C4DE;
-
+$color-lightgrey: #d3d3d3;
+$color-grey: #808080;
+$color-lightgrey-transparent: rgba(211, 211, 211, .9);
+$color-lightsteelgrey-transparent: rgba(190, 195, 221, .9);
+$color-lightsteelblue: #B0C4DE;
+$color-lightsteelblue-transparent: rgba(176, 196, 222, .9);
 
+$padding-top-fixed: 155px;
+$padding-bottom-fixed: 45px;

+ 38 - 3
src/styles/base/_base.scss

@@ -1,6 +1,41 @@
-a:hover {
-	text-decoration: none;
+body {
+    margin: 0;
 }
-a{
+
+a, a:hover {
     text-decoration: none;
+    color: black;
+}
+
+h1, h2, h3, h4 {
+    margin: 0
+}
+
+ul {
+    list-style-type: none;
+    padding: 0;
+    margin: 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;
+}
+
+// recheck
+
+@media screen and (max-width: 1200px) {
+    * {
+        transition: none !important;
+    }
 }

+ 3 - 0
src/styles/base/_typography.scss

@@ -0,0 +1,3 @@
+@import url("https://fonts.googleapis.com/css?family=Cormorant+Infant");
+@import url("https://fonts.googleapis.com/css?family=Open+Sans+Condensed:300");
+@import url("https://fonts.googleapis.com/css?family=Poiret+One");

+ 39 - 0
src/styles/components/_button.scss

@@ -0,0 +1,39 @@
+.link {
+    &--btn {
+        text-transform: uppercase;
+        font-family: 'Poiret One', cursive;
+        font-weight: bold;
+        cursor: pointer;
+        padding: 1.5vh 3vh;
+        background: $color-lightgrey-transparent;
+        box-shadow: 0 0 10px $color-grey;
+        border: none;
+            @media screen and (min-width: 1200px) {
+                transition: transform 200ms ease-in-out !important;
+                &:hover {
+                    transform: scale(1.2, 1.2) !important;
+                }
+            }
+        &50 {
+            width: 50%;
+        }
+        &60 {
+            width: 60%;
+        }
+        &75 {
+            width: 75%;
+        }
+        &100 {
+            width: 100%;
+        }
+        &-big {
+            font-size: 30px;
+            padding: 3vh 6vh;
+            font-weight: 400;
+        }
+        &-right {
+            float: right;
+        }
+    }
+    
+}

+ 31 - 0
src/styles/components/_categoriesPage.scss

@@ -0,0 +1,31 @@
+
+
+.categories {
+    &-page {
+        width: 95%;
+        margin: auto;
+    }
+    &-grid {
+        display: flex;
+        flex-wrap: wrap;
+        font-family: 'Cormorant Infant', serif;
+        text-align: center;
+        &__element {
+            min-width: 250px;
+            max-width: 370px;
+            margin: 1vw auto;
+            border: 2px solid lightsteelblue;
+            height: 300px;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+        }
+        &__content-wrapper {
+            width: 80%;
+            height: 80%;
+        }
+        .divider {
+            width: 60%;
+        }
+    }
+}

+ 5 - 0
src/styles/components/_container.scss

@@ -0,0 +1,5 @@
+.container {
+    margin: auto;
+    background: $color-lightgrey-transparent;
+    box-shadow: 0 0 10px grey;
+}

+ 0 - 0
src/styles/components/_createTestPage.scss


+ 23 - 0
src/styles/components/_footer.scss

@@ -0,0 +1,23 @@
+.footer {
+    text-align: center;
+    background: lightgray;
+
+    padding: 15px;
+    font-family: 'Cormorant Infant', serif;
+    font-weight: bold;
+    outline: 1px solid grey;
+    &__us {
+        font-size: 18px;
+        .us__inline {
+            &--red {
+                color: $color-red;
+            }
+            &--green {
+                color: $color-green;
+            }
+        }
+    }
+    &__copyright {
+        font-size: 14px;
+    }
+}

+ 152 - 27
src/styles/components/_header.scss

@@ -1,32 +1,157 @@
 .header {
-	background-color: $color_lightsteelblue;
-	padding: 2rem;
+    position: fixed;    
+    top: 0;
+    background: $color-lightsteelblue-transparent;
+    height: 130px;
+    width: 100%;
+    &__logo {
+        padding-top: 10px; 
+        margin: 0;
+        text-align: center;
+        &::first-letter {
+            color: $color-red;
+        }
+        &--i-letter {
+            color: $color-green;
+        }
+        &--divider {
+            width: 30%;
+            margin: auto;
+            margin-top: 5px;
+        }
+    }
 
-	display: flex;
-	
-	align-items: center;
+    &__flex-wrapper {
+        margin: auto;
+        margin-top: 20px;
+        width: 95%;
+        display: flex;
+        justify-content: space-between;
+    }
 
-	&__nav {
-		margin-right: 1rem;
-	}
-	&__nav-item {
-		padding: 2rem 2rem;
-		margin: 1rem;
-		transition: all 2s;
-		color: aliceblue;
-		&:hover {
-			background-color: $color-blue;
-			z-index: 1;
-			border-radius: 70px;
-		}
-	}
-	&__input_s{
-		margin: 0  15px 0 auto;
-	}
-	&__profile{
-		height: 50px;
-		border-radius: 50%;
-	}
-}
+    nav {
+        font-family: 'Poiret One', cursive;
+        font-weight: bold;
+        ul {
+            display: flex;
+            margin-bottom: 25px;
 
+            li {
+                a {
+                    color: $color-white;
+                    text-shadow: 1px 1px 2px black;
+                    font-size: 22px;
+                    transition: all 300ms ease-in-out;
+                    padding: 10px 20px;
+                }
+                .nav__list-item--admin-only {
+                    color: orange;
+                }
+                a:hover {
+                    border-bottom: 2px solid white;
+                    background: $color-lightgrey-transparent;
+                }
+                .nav__list-item--admin-only:hover {
+                    border-bottom: 2px solid orange;
+                    background: $color-lightgrey-transparent;
+                }
+            }
+        }
+    }
 
+    .header__links {
+        &--sign-in {
+            margin-right: 1.5vw;
+        }
+        &--sign-up {
+            margin-right: 20px;
+        }
+    }
+    
+    @media screen and (max-width: 1200px) {
+        &__flex-wrapper {
+            width: 100%;
+            display: block;
+            margin-top: 15px;
+        }
+        &__toggle-trigger {
+            position: absolute;
+            top: 70%;
+            cursor: pointer;
+            left: 0;
+            margin-left: 1em;
+            & span,
+            & span::after,
+            & span::before {
+                display: block;
+                height: 2px;
+                width: 2em;
+                border-radius: 2px;
+                background: white;
+            }
+            & span {
+                position: relative;
+            }
+            & span::after,
+            & span::before {
+                position: absolute;
+                content: "";
+            }
+            & span::after {
+                top: 7px;
+            }
+            & span::before {
+                bottom: 7px;
+            }
+        }
+        .toggle-status {
+            &--closed {
+                transform: scale(1, 0);
+            }
+            &--opened {
+                transform: scale(1, 1);
+            }
+        }
+        nav {
+            position: absolute;
+            width: 100%;
+            top: 100%;
+            
+            background: $color-lightsteelgrey-transparent;
+            transition: transform 400ms ease-in-out;
+            transform-origin: top;
+            & a {
+                font-size: 18px;
+            }
+            & a:hover {
+                font-size: 22px;
+            }
+            ul {
+                display: block;
+                margin: 0;
+            }
+            ul li {
+                padding: 1em;
+                border-bottom: 1px solid $color-lightgrey;
+                a {
+                    transition: none !important;
+                    padding: 0;
+                }
+            }
+            ul li:first-of-type {
+                border-top: 1px solid $color-lightgrey;
+            }
+        }
+        .header__links {
+            display: flex;
+            justify-content: center;
+
+            &--sign-in {
+                margin-right: 1.5vw;
+            }
+            &--sign-up {
+                margin-left: 1.5vw;
+            }
+        }
+    }
+}

+ 64 - 0
src/styles/components/_landingPage.scss

@@ -0,0 +1,64 @@
+.landing-page {
+    background-image: url('https://structureofintellect.files.wordpress.com/2017/09/bubble-test.jpg');
+    background-attachment: fixed;
+    background-repeat: no-repeat;
+    background-size: cover;
+    background-position: top center;
+    font-family: 'Cormorant Infant', serif;
+    &__about {
+        width: 65%;
+        text-align: center;
+        padding: 25px 40px;
+        .description {
+            &__inline {
+                &--pretty {
+                    color: seagreen;
+                    text-transform: uppercase;
+                    font-weight: bold;
+                }
+            }
+            &__divider {
+                width: 60%;
+            }
+            &__main {
+                font-size: 20px;
+            }
+        }
+    }
+    &__links-container {
+        margin-top: 45px;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-between;
+        width: 25%;
+        padding: 9vh;
+    }
+    // not correct spelling -> have to ask && change
+    &__links {
+        border: none;
+        box-shadow: 0 0 10px grey;
+        background: rgba(232,230, 230, 0.9);
+        padding: 3vh 0;
+        margin: 5px;
+        text-transform: uppercase;
+        font-family: 'Cormorant Infant', serif;
+        font-weight: bold;
+        font-size: 16px;
+        text-align: center;
+        width: 20vh;
+            @media screen and (max-width: 1125px) {
+                width: 100%;
+            }
+        transition: all 0.6s ease-in-out;
+    }
+    &__links:hover {
+        transform: rotate(360deg);
+    }
+
+    &__links--sign-in, {
+        color: orangered;
+    }
+    &__links--sign-up {
+        color: green;
+    }
+}

+ 24 - 0
src/styles/components/_notFound.scss

@@ -0,0 +1,24 @@
+.not-found {
+    text-align: center;
+    font-family: 'Poiret One', cursive;
+    
+    &__image {
+        display: block;
+        margin: auto;
+        width: 40%;
+    }
+    &__divider {
+        margin: 25px auto;
+        width: 40%;
+    }
+    &__message {
+        margin-bottom: 8vh;
+    }
+    &__link {
+        &--home {
+            font-size: 2.1em;
+            padding: 3vh 6vh;
+            margin-top: 35px;
+        }
+    }
+}

+ 16 - 0
src/styles/components/_page.scss

@@ -0,0 +1,16 @@
+.page {
+    padding-top: $padding-top-fixed;
+    padding-bottom: $padding-bottom-fixed;
+    &--bottom-only {
+        padding-top: $padding-top-fixed - 40px;
+    }
+}
+
+// .app {
+//     background-image: url('https://structureofintellect.files.wordpress.com/2017/09/bubble-test.jpg');
+//     background-attachment: fixed;
+//     background-repeat: no-repeat;
+//     background-size: cover;
+//     background-position: top center;
+// }
+    

+ 30 - 0
src/styles/components/_profilePage.scss

@@ -0,0 +1,30 @@
+.profile-page {
+    display: flex;
+    flex-wrap: wrap;
+    font-family: 'Cormorant Infant', serif;
+    font-size: 20px;
+    .section {
+        flex-grow: 1;
+        flex-basis: 400px;
+        margin: 10px;
+        padding: 10px;
+        &__element {
+            &--image {
+                border: 3px solid $color-lightsteelblue;
+                margin-bottom: 20px;
+            }
+            p {
+                margin-top: 5px;
+            }
+            .comments-block {
+                height: 250px;
+                overflow: auto;
+            }
+            
+        }
+    }
+    .right {
+        float: right;
+    }
+}
+

+ 62 - 0
src/styles/components/_signPage.scss

@@ -0,0 +1,62 @@
+.sign {
+    &-form {
+        // background: $color-lightgrey-transparent;
+        font-size: 18px;
+        font-family: 'Poiret One', cursive;
+        font-weight: bold;
+        display: block;
+        margin: auto;
+        border: 3px solid $color-lightgrey;
+        outline: 1px solid $color-grey;
+        padding: 25px;
+        width: 45%;
+        @media screen and (max-width: 480px) {
+            width: 75%;
+        }
+        text-align: center;
+        &__input,
+        &__submit-button {
+            width: 80%;
+        }
+        &__header {
+            margin: 0 0 35px 0;
+        }
+        &__password-container {
+            margin: 50px 0;
+        }
+        &__input {
+            display: block;
+            margin: 25px auto;
+            border: 1px solid $color-lightgrey;
+            padding: 15px;
+            box-shadow: 0 0 3px $color-grey;
+
+            &--login {}
+            &--password {}
+        }
+        &__input::placeholder {
+            font-family: 'Poiret One', cursive;
+            font-size: 18px;
+            font-weight: bold;
+        }
+        &__submit-button {
+            
+        }
+        &__link {
+            &--with-margin {
+                margin-bottom: 20px;
+            }
+            &--sign-up a{
+                color: $color-green;
+                text-transform: uppercase;
+                transition: all 100ms ease-in-out;
+            }
+            &--sign-up a:hover{
+                font-size: 23px;
+            }
+        }
+        &__divider {
+            width: 60%;
+        }
+    }
+}

+ 7 - 0
src/styles/components/_spinner.scss

@@ -0,0 +1,7 @@
+.spinner {
+    height: 100vh;
+
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}

+ 15 - 1
src/styles/index.scss

@@ -1,3 +1,17 @@
 @import "abstracts/variables";
-@import "components/header";
+
 @import "base/base";
+@import "base/typography";
+
+@import "components/page";
+@import "components/container";
+@import "components/button";
+@import "components/header";
+@import "components/spinner";
+@import "components/landingPage";
+@import "components/footer";
+@import "components/signPage";
+@import "components/notFound";
+@import "components/profilePage";
+@import "components/categoriesPage";
+

+ 1 - 0
src/utils/token.js

@@ -0,0 +1 @@
+export default "fake-token-lol-kek";

+ 6 - 0
грабли.txt

@@ -0,0 +1,6 @@
+1. Редакс ломает роутер.
+Возможный костыль:
+https://github.com/ReactTraining/react-router/blob/v4.0.0-beta.8/packages/react-router/docs/guides/blocked-updates.md
+2. Анимация на кнопках хэдэра и нотфаунд не работает, хотя работает на кнопках формы.
+ХЗ
+3. Нету адекватного способа прокинуть юзера в роутер -> см. пункт 1.

+ 1 - 0
костыли.txt

@@ -0,0 +1 @@
+Все еще впереди...