6 次代码提交 939956eb6e ... 44569b3daa

作者 SHA1 备注 提交日期
  Svetlana 44569b3daa marge -> sineIn, sineUp and profile 5 年之前
  Svetlana b46a81722c profile 5 年之前
  Maxim 1fa808c423 sign up is finally done 5 年之前
  Maxim 3dd80863d5 signUp -> validation and form added, reducer is done 5 年之前
  sveta c9fa754a79 profile->login 5 年之前
  Maxim f952c35f77 user storaging via redux is done -> router works correctly 5 年之前
共有 44 个文件被更改,包括 829 次插入194 次删除
  1. 4 9
      package-lock.json
  2. 3 0
      src/actions/auth/logOut.js
  3. 0 0
      src/actions/auth/saveToken.js
  4. 4 7
      src/actions/auth/signIn.js
  5. 17 0
      src/actions/user/changeEmail.js
  6. 17 0
      src/actions/user/changePassword.js
  7. 17 0
      src/actions/user/changelogin.js
  8. 25 0
      src/components/admin/deleteUser/DeleteUserForm/index.js
  9. 31 0
      src/components/admin/deleteUser/index.js
  10. 1 3
      src/components/common/protectedRoute.js
  11. 1 1
      src/components/common/spinner.js
  12. 45 44
      src/components/public/Header.js
  13. 28 23
      src/components/public/SignIn/Form/index.js
  14. 23 21
      src/components/public/SignIn/index.js
  15. 63 0
      src/components/public/SignUp/Form/index.js
  16. 47 0
      src/components/public/SignUp/Form/validate.js
  17. 31 0
      src/components/public/SignUp/index.js
  18. 44 0
      src/components/user/ProfilePage/ChangeEmailForm/index.js
  19. 24 4
      src/components/user/ProfilePage/ChangeLoginForm/index.js
  20. 47 0
      src/components/user/ProfilePage/changePassword/index.js
  21. 77 47
      src/components/user/ProfilePage/index.js
  22. 6 5
      src/configs/routerConfig.js
  23. 1 1
      src/constants/auth.js
  24. 12 0
      src/constants/user.js
  25. 0 2
      src/index.js
  26. 8 3
      src/reducers/auth/signIn.js
  27. 8 4
      src/reducers/auth/signUp.js
  28. 9 1
      src/reducers/index.js
  29. 13 2
      src/reducers/initialState.js
  30. 37 0
      src/reducers/user/chageLogin.js
  31. 37 0
      src/reducers/user/changeEmail.js
  32. 3 9
      src/router.js
  33. 0 1
      src/sagas/auth/index.js
  34. 4 3
      src/sagas/auth/signIn.js
  35. 24 2
      src/sagas/auth/signUp.js
  36. 3 1
      src/sagas/index.js
  37. 27 0
      src/sagas/user/changeEmail.js
  38. 27 0
      src/sagas/user/changeLogin.js
  39. 28 0
      src/sagas/user/changePassword.js
  40. 15 0
      src/sagas/user/index.js
  41. 3 1
      src/styles/_index.scss
  42. 0 0
      src/styles/abstracts/_theme.scss
  43. 14 0
      src/styles/extended/_vh.scss
  44. 1 0
      src/utils/storageKey.js

+ 4 - 9
package-lock.json

@@ -5731,8 +5731,7 @@
         },
         "ansi-regex": {
           "version": "2.1.1",
-          "bundled": true,
-          "optional": true
+          "bundled": true
         },
         "aproba": {
           "version": "1.2.0",
@@ -6084,8 +6083,7 @@
         },
         "safe-buffer": {
           "version": "5.1.1",
-          "bundled": true,
-          "optional": true
+          "bundled": true
         },
         "safer-buffer": {
           "version": "2.1.2",
@@ -6132,7 +6130,6 @@
         "strip-ansi": {
           "version": "3.0.1",
           "bundled": true,
-          "optional": true,
           "requires": {
             "ansi-regex": "^2.0.0"
           }
@@ -6171,13 +6168,11 @@
         },
         "wrappy": {
           "version": "1.0.2",
-          "bundled": true,
-          "optional": true
+          "bundled": true
         },
         "yallist": {
           "version": "3.0.2",
-          "bundled": true,
-          "optional": true
+          "bundled": true
         }
       }
     },

+ 3 - 0
src/actions/auth/logOut.js

@@ -0,0 +1,3 @@
+export const logOut = () => ({
+    
+})

+ 0 - 0
src/actions/auth/saveToken.js


+ 4 - 7
src/actions/auth/signIn.js

@@ -1,12 +1,9 @@
 import * as actionTypes from './../../constants/auth';
 
-export const signIn = payload => {
-    console.log('Inside the signIn action', payload);
-    return {
-        type: actionTypes.SIGN_IN_REQUEST,
-        payload
-    };
-}
+export const signIn = payload => ({
+    type: actionTypes.SIGN_IN_REQUEST,
+    payload
+});
 export const signInSuccess = payload => ({
     type: actionTypes.SIGN_IN_REQUEST_SUCCESS,
     payload

+ 17 - 0
src/actions/user/changeEmail.js

@@ -0,0 +1,17 @@
+import * as actionTypes from './../../constants/user';
+
+export const changeEmailRequest = payload => {
+    console.log('Inside the changeEMAIL action', payload);
+    return {
+        type: actionTypes.CHANGE_EMAIL_REQUEST,
+        payload
+    };
+}
+export const changeEmailSuccess = payload => ({
+    type: actionTypes.CHANGE_EMAIL_REQUEST_SUCCESS,
+    payload
+});
+export const changeEmailFailure = error => ({
+    type: actionTypes.CHANGE_EMAIL_REQUEST_FAILURE,
+    error
+});

+ 17 - 0
src/actions/user/changePassword.js

@@ -0,0 +1,17 @@
+import * as actionTypes from './../../constants/user';
+
+export const changePasswordRequest = payload => {
+    console.log('Inside the changePassword action', payload);
+    return {
+        type: actionTypes.CHANGE_PASSWORD_REQUEST,
+        payload
+    };
+}
+export const changePasswordSuccess = payload => ({
+    type: actionTypes.CHANGE_PASSWORD_REQUEST_SUCCESS,
+    payload
+});
+export const changePasswordFailure = error => ({
+    type: actionTypes.CHANGE_PASSWORD_REQUEST_FAILURE,
+    error
+});

+ 17 - 0
src/actions/user/changelogin.js

@@ -0,0 +1,17 @@
+import * as actionTypes from './../../constants/user';
+
+export const changeLoginRequest = payload => {
+    console.log('Inside the changeLogin action', payload);
+    return {
+        type: actionTypes.CHANGE_LOGIN_REQUEST,
+        payload
+    };
+}
+export const changeLoginSuccess = payload => ({
+    type: actionTypes.CHANGE_LOGIN_REQUEST_SUCCESS,
+    payload
+});
+export const changeLoginFailure = error => ({
+    type: actionTypes.CHANGE_LOGIN_REQUEST_FAILURE,
+    error
+});

+ 25 - 0
src/components/admin/deleteUser/DeleteUserForm/index.js

@@ -0,0 +1,25 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { Field, reduxForm } from 'redux-form';
+
+import formInput from '../../../common/formInput';
+
+class DeleteUserForm extends React.Component {
+
+    render() {
+        return (
+            <form>
+                <Field name="name" type="name" placeholder="Enter login" component={formInput} />
+                <button
+                    type="button" className="link link--btn right"        
+                    >
+                    Search
+                </button>
+            </form >
+        )
+    }
+}
+
+export default reduxForm({
+    form: "deleteUserForm",
+})(DeleteUserForm);

+ 31 - 0
src/components/admin/deleteUser/index.js

@@ -0,0 +1,31 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux'
+import DeleteUserForm from './DeleteUserForm/index'
+
+
+
+class ProfilePage extends React.Component {
+    
+
+    render() {
+       
+        return (
+            <div>
+                <input type="file"/>
+                <DeleteUserForm></DeleteUserForm>
+            </div>
+            
+        )
+    }
+
+}
+
+const
+    mapStateToProps = state => ({
+
+    });
+
+const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(ProfilePage);

+ 1 - 3
src/components/common/protectedRoute.js

@@ -23,9 +23,7 @@ export default ({ component: Component, user, tokenAuth, access, ...rest }) => (
             } */}
             const checkedData = user && user.data ? user.data : null;
 
-            console.log('Component', Component);
-            console.log('Access', access);
-            console.log('User Data', checkedData);
+            console.log('\n\nHere goes the route:', '\nUser', user, '\n\n\n')
 
             if (access === 'public') {
                 return <Component {...props} />

+ 1 - 1
src/components/common/spinner.js

@@ -1,7 +1,7 @@
 import React from 'react';
 
 export default () => (
-    <div class="d-flex justify-content-center">
+    <div className="container d-flex align-items-center justify-content-center">
         <div class="spinner-border" role="status">
             <span class="sr-only">Loading...</span>
         </div>

+ 45 - 44
src/components/public/Header.js

@@ -5,54 +5,55 @@ import * as routes from '../../constants/routes'
 export default class Header extends React.Component {
     render() {
         return (
-            <div className="row">
-                <div className="container-fluid">
-                    <nav class="navbar navbar-expand-lg navbar-dark bg-dark mb-2">
-                        <a class="navbar-brand" href="#">Test.io</a>
-                        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
-                            <span class="navbar-toggler-icon"></span>
-                        </button>
+            <nav class="navbar navbar-expand-lg navbar-dark bg-dark p-3">
+                <a class="navbar-brand" href="#">Test.io</a>
+                <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
+                    <span class="navbar-toggler-icon"></span>
+                </button>
 
-                        <div class="collapse navbar-collapse" id="navbarSupportedContent">
-                            <ul class="navbar-nav mr-auto p-3">
-                                <li class="nav-item active">
-                                <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold" to={routes.HOME}>Home <span class="sr-only">(current)</span></Link>
-                                </li>
-                                <li class="nav-item">
-                                <Link onClick={this.handleClick}  class="nav-link font-ci font-ci-bold"  to={routes.PROFILE}>Profile</Link>
-                                </li>
-                                <li class="nav-item">
-                                <Link onClick={this.handleClick}  class="nav-link font-ci font-ci-bold "  to={routes.TESTS}>Tests</Link>
-                                </li>
-                                <li class="nav-item">
-                                <Link onClick={this.handleClick}  class="nav-link font-ci font-ci-bold "  to={routes.CATEGORIES}>Catigories</Link>
-                                </li>
-                                {/* TODO: admin-only ! */}
-                                <li class="nav-item dropdown">
-                                    <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
-                                        Dropdown
+                <div class="collapse navbar-collapse" id="navbarSupportedContent">
+                    <ul class="navbar-nav mr-auto">
+                        <li class="nav-item active">
+                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold" to={routes.HOME}>Home <span class="sr-only">(current)</span></Link>
+                        </li>
+                        <li class="nav-item">
+                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold" to={routes.PROFILE}>Profile</Link>
+                        </li>
+                        <li class="nav-item">
+                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.TESTS}>Tests</Link>
+                        </li>
+                        <li class="nav-item">
+                            <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.CATEGORIES}>Catigories</Link>
+                        </li>
+                        {/* TODO: admin-only ! */}
+                        <li class="nav-item dropdown">
+                            <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
+                                Menu Admina
                                     </a>
-                                    <div class="dropdown-menu" aria-labelledby="navbarDropdown">
-                                        <a class="dropdown-item" href="#">Action</a>
-                                        <a class="dropdown-item" href="#">Another action</a>
-                                        <div class="dropdown-divider"></div>
-                                        <a class="dropdown-item" href="#">Something else here</a>
-                                    </div>
-                                </li>
-                               
-                            </ul>
-                            <form class="form-inline my-2 my-lg-0">
-                                <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
-                                <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
-                            </form>
-                            <div className="btn-group ml-2" role="group">
-                                <button className="btn btn-secondary">Sign In</button>
-                                <button className="btn btn-secondary">Sign Up</button>
+                            <div class="dropdown-menu" aria-labelledby="navbarDropdown">
+                                <Link onClick={this.handleClick} class="nav-link font-ci font-ci-bold " to={routes.DELETE_USER}>Delete</Link>
+                                <a class="dropdown-item" href="#">Action</a>
+                                <a class="dropdown-item" href="#">Another action</a>
+                                <div class="dropdown-divider"></div>
+                                <a class="dropdown-item" href="#">Something else here</a>
                             </div>
-                        </div>
-                    </nav>
+                        </li>
+
+                    </ul>
+                    <form class="form-inline my-2 my-lg-0">
+                        <input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search" />
+                        <button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
+                    </form>
+                    <div className="pl-2">
+                        <Link to={routes.SIGN_IN}>
+                            <button className="btn btn-outline-primary">Sign In</button>
+                        </Link>
+                        <Link to={routes.SIGN_UP}>
+                            <button className="btn btn-outline-primary ml-2">Sign Up</button>
+                        </Link>
+                    </div>
                 </div>
-            </div>
+            </nav>
         )
     }
 }

+ 28 - 23
src/components/public/SignIn/Form/index.js

@@ -1,7 +1,5 @@
 import React from 'react';
 import { reduxForm, Field } from 'redux-form';
-import { connect } from 'react-redux';
-import { bindActionCreators } from 'redux';
 
 import validate from './validate';
 import formInput from './../../../common/formInput';
@@ -17,30 +15,37 @@ class Form extends React.Component {
     }
 
     render() {
-        const { handleSubmit, error } = this.props;
+        const { handleSubmit, requestError, invalid } = this.props;
 
         return (
-            <form className="text-center" onSubmit={handleSubmit(this.submit)}>
-                {
-                    error
-                        ?
-                        <p className="text-af text-uppercase">{error}</p>
-                        :
-                        null
-                }
-
-                <div className="form-group">
-                    <label className="text-uppercase">Email address</label>
-                    <Field type="email" name='email' className="form-control" placeholder="name@example.com" component={formInput} />
+            <div className="container">
+                <div className="row">
+                    <div className="col-md-8 col-10 col-lg-6 m-auto p-4 border rounded">
+
+                        <form className="text-center" onSubmit={handleSubmit(this.submit)}>
+                            {
+                                requestError
+                                    ?
+                                    <p className="text-af text-uppercase">{requestError}</p>
+                                    :
+                                    null
+                            }
+
+                            <div className="form-group">
+                                <label className="text-uppercase">Email address</label>
+                                <Field type="email" name='email' className="form-control" placeholder="name@example.com" component={formInput} />
+                            </div>
+
+                            <div className="form-group">
+                                <label className="text-uppercase">Password</label>
+                                <Field type="password" name='password' className="form-control" component={formInput} />
+                            </div>
+
+                            <button type="submit" className="btn btn-primary" disabled={invalid}>Sign In!</button>
+                        </form>
+                    </div>
                 </div>
-
-                <div className="form-group">
-                    <label className="text-uppercase">Password</label>
-                    <Field type="password" name='password' className="form-control" placeholder="example123" component={formInput} />
-                </div>
-
-                <button type="submit" className="btn btn-primary">Sign In!</button>
-            </form>
+            </div>
         )
     }
 }

+ 23 - 21
src/components/public/SignIn/index.js

@@ -7,27 +7,29 @@ import { Redirect } from 'react-router-dom'
 import Spinner from './../../common/spinner';
 import { signIn } from './../../../actions/auth/signIn';
 
-const SignIn = ({ signIn, user }) => (
-    <div className="row">
-        <div className="container">
-            <div className="col-4 m-auto p-4 border rounded">
-                {
-                    user.isFetching
-                        ?
-                        <Spinner />
-                        : user.data
-                            ?
-                            <Redirect to='/' />
-                            : user.error
-                                ?
-                                <Form error={user.error} signIn={signIn} />
-                                :
-                                <Form signIn={signIn} />
-                }
-            </div>
-        </div>
-    </div>
-)
+const SignIn = ({ signIn, user }) => {
+    const someShit = user.isFetching
+        ?
+        <Spinner />
+        : user.data
+            ?
+            <Redirect to='/' />
+            : user.error
+                ?
+                (
+                    <React.Fragment>
+                        <Form signIn={signIn} requestError={user.error} />
+                    </React.Fragment>
+
+                )
+                :
+                <Form signIn={signIn} />
+
+    return someShit
+
+}
+
+
 
 const mapStateToProps = state => ({
     user: state.signIn

+ 63 - 0
src/components/public/SignUp/Form/index.js

@@ -0,0 +1,63 @@
+import React from 'react';
+import { reduxForm, Field } from 'redux-form';
+
+import validate from './validate';
+import formInput from './../../../common/formInput';
+
+class Form extends React.Component {
+
+    submit = ({ name, email, password }) => {
+        const { signUp } = this.props;
+        signUp({
+            name,
+            email,
+            password
+        })
+    }
+
+    render() {
+        const { handleSubmit, requestError, invalid } = this.props;
+
+        return (
+            <div className="container">
+                <div className="row">
+                    <div className="col-md-8 col-10 col-lg-6 m-auto p-4 border rounded">
+
+                        <form className="text-center" onSubmit={handleSubmit(this.submit)}>
+                            {
+                                requestError
+                                    ?
+                                    <p className="text-af text-uppercase">{requestError}</p>
+                                    :
+                                    null
+                            }
+
+                            <div className="form-group border p-4">
+                                <label className="text-uppercase">Name</label>
+                                <Field type="text" name='name' className="form-control" placeholder="example" component={formInput} />
+
+                                <label className="text-uppercase pt-3">Email address</label>
+                                <Field type="email" name='email' className="form-control" placeholder="name@example.com" component={formInput} />
+                            </div>
+
+                            <div className="form-group border p-4">
+                                <label className="text-uppercase">Password</label>
+                                <Field type="password" name='password' className="form-control" component={formInput} />
+
+                                <label className="text-uppercase pt-3">Password Confirmation</label>
+                                <Field type="password" name='passwordConfirmation' className="form-control" component={formInput} />
+                            </div>
+
+                            <button type="submit" className="btn btn-primary" disabled={invalid}>Sign In!</button>
+                        </form>
+                    </div>
+                </div>
+            </div>
+        )
+    }
+}
+
+export default reduxForm({
+    form: "SignUp",
+    validate
+})(Form)

+ 47 - 0
src/components/public/SignUp/Form/validate.js

@@ -0,0 +1,47 @@
+export default function validate(values) {
+    const { name, email, password, passwordConfirmation } = values;
+    const errors = {};
+
+    if (!email) {
+        errors.email = "Required";
+    }
+    else if (email.length < 8 || email.length > 20) {
+        errors.email = "Invalid email length: email 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(email)) {
+        errors.email = "Invalid email, try another one";
+    }
+
+    if (!name) {
+        errors.name = "Required";
+    }
+    else if (name.length < 6 || name.length > 10) {
+        errors.name = "Invalid name length: name should be from 6 to 10 symbols";
+    }
+    else if (!/^[_A-z0-9]*((-|\s)*[_A-z0-9])*$/.test(name)) {
+        errors.name = "Invalid name, 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;
+}

+ 31 - 0
src/components/public/SignUp/index.js

@@ -0,0 +1,31 @@
+import React from 'react';
+import Form from './Form';
+import { bindActionCreators } from 'redux';
+import { connect } from 'react-redux';
+import { Redirect } from 'react-router-dom';
+
+import Spinner from './../../common/spinner';
+import { signUp } from './../../../actions/auth/signUp';
+
+const SignUp = ({ status, signUp }) => (
+    status.isFetching
+        ?
+        <Spinner />
+        : status.isSuccessful
+            ?
+            <Redirect to='/sign-in' />
+            : status.error
+                ?
+                <Form signUp={signUp} requestError={status.error} />
+                :
+                <Form signUp={signUp} />
+)
+
+const mapStateToProps = state => ({
+    status: state.signUp
+});
+const mapDispatchToProps = dispatch => bindActionCreators({
+    signUp
+}, dispatch);
+
+export default connect(mapStateToProps, mapDispatchToProps)(SignUp);

+ 44 - 0
src/components/user/ProfilePage/ChangeEmailForm/index.js

@@ -0,0 +1,44 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { Field, reduxForm } from 'redux-form';
+
+import formInput from '../../../common/formInput';
+
+class ChangeEmailForm extends React.Component {
+
+    submit = ({email}) => {
+        const {actions:{changeEmailRequest},data:{_id},token } = this.props
+        console.log(_id, email,token);
+
+        changeEmailRequest({
+            token,
+           _id,
+            email
+        })
+        
+    }
+
+    render() {
+        const { children, handleSubmit, actions:{changeEmailRequest}, handlers: {  handleClick, handleClicks }, data, token } = this.props;
+        const { submit}=this
+        return (
+            <form onSubmit={handleSubmit(submit)} >
+                <Field name="email" type="email" placeholder="Enter new login" component={formInput} />
+                <button
+                    type="button" className="link link--btn right"  onClick={
+                        function() {
+                        handleClicks();
+                            handleSubmit(submit)();
+                        }    
+                    
+                    }>
+                    Change
+                </button>
+            </form >
+        )
+    }
+}
+
+export default reduxForm({
+    form: "changeEmailForm",
+})(ChangeEmailForm);

+ 24 - 4
src/components/user/ProfilePage/ChangeLoginForm/index.js

@@ -6,13 +6,33 @@ import formInput from '../../../common/formInput';
 
 class ChangeLoginForm extends React.Component {
 
+    submit = ({ name}) => {
+        const {actions:{changeLoginRequest},data:{_id},token } = this.props
+        console.log(_id, name,token);
+
+        changeLoginRequest({
+            token,
+           _id,
+            name
+        })
+        
+    }
+
     render() {
-        // const { children, handleSubmit, handlers: { handleClick, submit } } = this.props;
+        const { children, handleSubmit, actions:{changeLoginRequest}, handlers: {  handleClick }, data, token } = this.props;
+        const { submit}=this
+        console.log( data)
         return (
-            <form  >
-                <Field name="login" type="email" placeholder="Enter new login" component={formInput} />
+            <form onSubmit={handleSubmit(submit)} >
+                <Field name="name" type="email" placeholder="Enter new login" component={formInput} />
                 <button
-                    type="button" className="link link--btn right" >
+                    type="button" className="link link--btn right"  onClick={
+                        function() {
+                        handleClick();
+                            handleSubmit(submit)();
+                        }    
+                    
+                    }>
                     Change
                 </button>
             </form >

+ 47 - 0
src/components/user/ProfilePage/changePassword/index.js

@@ -0,0 +1,47 @@
+import React from 'react';
+import { Field, reduxForm } from 'redux-form';
+
+import formInput from '../../../common/formInput';
+
+class ChangePasswordForm extends React.Component {
+
+    submit = ({password, confirmPassword }) => {
+        const {actions:{changePasswordRequest},data:{_id},token } = this.props
+        console.log(_id, password, confirmPassword, token);
+
+        changePasswordRequest({
+            token,
+           _id,
+            password,
+            confirmPassword
+        })
+        
+    }
+
+    render() {
+        const { children, handleSubmit, actions:{ changePasswordRequest }, handlers: {  handleClicked }, data, token } = this.props;
+        const { submit}=this
+        console.log( data)
+        return (
+            <form onSubmit={handleSubmit(submit)} >
+                <Field name="password" type="password" placeholder="Password" component={formInput} />
+                <Field name="confirmPassword" type="password" placeholder="new Password" component={formInput} />
+
+                <button
+                    type="button" className="link link--btn right"  onClick={
+                        function() {
+                        handleClicked();
+                            handleSubmit(submit)();
+                        }    
+                    
+                    }>
+                    Change
+                </button>
+            </form >
+        )
+    }
+}
+
+export default reduxForm({
+    form: "changePasswordForm",
+})(ChangePasswordForm);

+ 77 - 47
src/components/user/ProfilePage/index.js

@@ -1,88 +1,117 @@
 import React from 'react';
 import { connect } from 'react-redux';
 import { bindActionCreators } from 'redux'
- import ChangeLoginForm from './ChangeLoginForm/index';
+import ChangeLoginForm from './ChangeLoginForm/index';
+import ChangeEmailForm from './ChangeEmailForm/index';
+import ChangePasswordForm from './changePassword/index'
+import {changeLoginRequest} from '../../../actions/user/changelogin';
+import {changeEmailRequest} from '../../../actions/user/changeEmail';
+import {changePasswordRequest } from '../../../actions/user/changePassword'
 
-const user = {
-    "data": {
-        "_id": "5c48461c40ca670017ba5974",
-        "name": "Debil",
-        "email": "superus@lol.com",
-        "password": "$2a$10$qoxrQ2Sp3BDTLa9Xdc0ZPuLVHamipMQRWxeWxw1RwthICnbPoFLvC",
-        "profilePhoto": "",
-        "role": 0
-    },
-    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVjNDg0NjFjNDBjYTY3MDAxN2JhNTk3NCIsInJvbGUiOjAsImlhdCI6MTU0ODI1NTczMiwiZXhwIjoxNTQ4MzQyMTMyfQ.RAIiCLjBJ2u1VEQWy1oUgPjHj0dZRG27l0J3c8FDss0"
-}
 
 class ProfilePage extends React.Component {
+    
     state={
-        clicked:false
+        clicked:false,
+        klick: false,
+        click: false
     }
 
     handleClick = () => {
         this.setState((prevState) => ({ clicked: !prevState.clicked }));
     }
+    handleClicks = () => {
+        this.setState((prevState) => ({ klick: !prevState.klick }));
+    }
+    handleClicked = () => {
+        this.setState((prevState) => ({ click: !prevState.click }));
+    }
 
     render() {
-        const { users, userChangeRequest, passwordChangeRequest } = this.props;
-        const { data } = user;
-        const {clicked} =this.state;
+        const { signIn:{data, token}, changeLoginRequest, chageLoginReducer, changeEmailRequest, changeEmailReducer, changePasswordRequest} = this.props;
+      console.log(changeEmailReducer)
+        const {clicked, klick, click} =this.state;
+        const {handleClick, handleClicks, handleClicked} = this;
 
         return (
             <div className="page page--bottom-only profile-page">
-                <section className="border bg-autumn-foliage m-5 rounded d-flex">
+                <div className="border bg-autumn-foliage m-5 rounded d-flex">
+                    <div>
+                {/* <h5 className="p-2 font-po-bold flex-fill bd-highlight align-self-end">{data.name}</h5> */}
+                {/* <div className="d-flex"  >
+                <p className="p-2 flex-fill font-po-bold bd-highlight align-self-end">Email</p><p className="p-2 flex-fill font-po-bold bd-highlight align-self-end">{data.email}</p>
+                </div> */}
+                {/* <div className="d-flex"  >
+                <p className="p-2 flex-fill font-po-bold bd-highlight align-self-end">Role</p><p className="p-2 flex-fill font-po-bold bd-highlight align-self-end">{data.role}</p>
+                </div> */}
+                
                     <div>
                         <img className="m-4 " src=" https://cdn.iconscout.com/icon/free/png-256/avatar-373-456325.png" ></img>
                     </div>
+                    </div>
                     <div className="border-left bg-autumn-foliage m-5 rounded w-75 ">
                             {!clicked
                             ?
                         <div  className ="d-flex mb-3" >
                             <h3 className = " p-2 flex-fill bd-highlight">Name</h3>
-                            <h5 className="p-2 font-po-bold flex-fill bd-highlight align-self-end">{data.name}</h5>
-                            <button type="button" onClick ={this.handleClick} className=" flex-fill bg-shadow btn btn-outline-light col-3">Change</button>
+                            <h5 className="p-2 font-po-bold flex-fill bd-highlight align-self-end">{
+                                chageLoginReducer.data == null
+                                ?
+                                data.name 
+                                :
+                                chageLoginReducer.data
+
+                                }</h5>
+                            <button type="button" onClick ={handleClick}  className=" flex-fill bg-shadow btn btn-outline-primary col-3">Change</button>
                         </div>
                         :
                         <div>
                         <h3 className = " p-2 flex-fill bd-highlight">Name</h3>
                         <h5 className="p-2 font-po-bold flex-fill bd-highlight align-self-end">{data.name}</h5>
-                        <ChangeLoginForm> </ChangeLoginForm>
+                        <ChangeLoginForm data ={data} token={token} actions ={{changeLoginRequest}} handlers={{ handleClick}}> </ChangeLoginForm>
                         </div>
                             }
+                            {!klick
+                            ?
+                        <div  className ="d-flex mb-3" >
+                            <h3 className = "p-2 flex-fill bd-highlight">Email</h3>
+                            <h5 className="p-2 flex-fill font-po-bold bd-highlight align-self-end">
+                                {
+                                    changeEmailReducer.data ===null
+                                    ?
+                                    data.email
+                                    :
+                                    changeEmailReducer.data
+                                }
+                            </h5>
+                            <button type="button" name ="name"  onClick ={handleClicks} className=" flex-fill bg-shadow btn btn-outline-primary col-3">Change</button>
+                        </div>
+                        :
                         <div  className ="d-flex mb-3" >
                             <h3 className = "p-2 flex-fill bd-highlight">Email</h3>
                             <h5 className="p-2 flex-fill font-po-bold bd-highlight align-self-end">{data.email}</h5>
-                            <button type="button" className=" flex-fill bg-shadow btn btn-outline-light col-3">Change</button>
+                            <ChangeEmailForm  data ={data} token={token} actions ={{changeEmailRequest}} handlers={{ handleClicks}}></ChangeEmailForm>
                         </div>
+                            }
+                            {
+                                !click
+                                ?
                         <div  className ="d-flex mb-3" >
                             <h3 className = "p-2 flex-fill bd-highlight">Password</h3>
-                            <button type="button" className=" flex-fill bg-shadow btn btn-outline-light col-3">Change</button>
+                            <button type="button" onClick ={handleClicked} className=" flex-fill bg-shadow btn btn-outline-primary col-3">Change</button>
+                        </div>
+                        :
+                        <div  className ="d-flex mb-3" >
+                            <h3 className = "p-2 flex-fill bd-highlight">Password</h3>
+                           <ChangePasswordForm data ={data} token={token} actions ={{changePasswordRequest}} handlers={{ handleClicked}}></ChangePasswordForm>
                         </div>
-                 
-                    </div>
-                </section>
-                <section className="container section section--stats">
-                    <div className="section__element section__element--">
-                        <h3>Member Since</h3>
-                        <p>{new Date(data.createdAt).toLocaleString()}</p>
-                    </div>
-                    <div className="section__element section__element--comments border-right-0">
-                        <h3>Last comments</h3>
-                        <p className="comments-block">
-                            {
-                                data.comments && data.comments
-                                    .slice(0, 60)
-                                    .map(el =>
-                                        <p>
-                                            <h4>{new Date(el.createdAt).toLocaleString()}</h4>
-                                            {el.text}
-                                        </p>)
                             }
-                        </p>
+                 
                     </div>
-                </section>
-            </div>
+                </div>
+                
+                </div>
+            
         )
     }
 
@@ -90,10 +119,11 @@ class ProfilePage extends React.Component {
 
 const
     mapStateToProps = state => ({
-        user: state.user,
-        users: state.users
+        signIn: state.signIn,
+        chageLoginReducer: state.chageLoginReducer,
+        changeEmailReducer:state.changeEmailReducer
     });
 
-const mapDispatchToProps = dispatch => bindActionCreators({}, dispatch);
+const mapDispatchToProps = dispatch => bindActionCreators({changeLoginRequest, changeEmailRequest, changePasswordRequest}, dispatch);
 
 export default connect(mapStateToProps, mapDispatchToProps)(ProfilePage);

+ 6 - 5
src/configs/routerConfig.js

@@ -1,10 +1,11 @@
 import React, { lazy } from 'react';
 import * as routes from './../constants/routes';
 
-const ProfilePage =lazy(()=> import('../components/user/ProfilePage'))
-
+const ProfilePage = lazy(() => import('../components/user/ProfilePage'))
+const DeleteUser = lazy(()=>import('../components/admin/deleteUser/index'))
 // import SignIn from '../components/public/SignIn';
-const SignIn = lazy(() => import('./../components/public/SignIn'))
+const SignIn = lazy(() => import('./../components/public/SignIn'));
+const SignUp = lazy(() => import('./../components/public/SignUp'));
 
 export default [
     {
@@ -20,7 +21,7 @@ export default [
     {
         path: routes.SIGN_UP,
         access: 'public',
-        component: () => <div>sign up</div>
+        component: SignUp
     },
     {
         path: routes.HOME,
@@ -45,7 +46,7 @@ export default [
     {
         path: routes.DELETE_USER,
         access: 'admin-only',
-        component: () => <div>delete user</div>
+        component: DeleteUser
     },
     {
         access: 'public',

+ 1 - 1
src/constants/auth.js

@@ -3,7 +3,7 @@ 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 = '';
+export const SIGN_UP_URL = 'https://test-app-a-level.herokuapp.com/auth/register';
 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';

+ 12 - 0
src/constants/user.js

@@ -0,0 +1,12 @@
+export const USER_URL = 'https://test-app-a-level.herokuapp.com/users/'; 
+export const CHANGE_LOGIN_REQUEST = 'CHANGE_LOGIN_REQUEST';
+export const CHANGE_LOGIN_REQUEST_SUCCESS = 'CHANGE_LOGIN_REQUEST_SUCCESS';
+export const CHANGE_LOGIN_REQUEST_FAILURE = 'CHANGE_LOGIN_REQUEST_FAILURE';
+
+export const CHANGE_EMAIL_REQUEST = 'CHANGE_EMAIL_REQUEST';
+export const CHANGE_EMAIL_REQUEST_SUCCESS = 'CHANGE_EMAIL_REQUEST_SUCCESS';
+export const CHANGE_EMAIL_REQUEST_FAILURE = 'CHANGE_EMAIL_REQUEST_FAILURE';
+
+export const CHANGE_PASSWORD_REQUEST = 'CHANGE_PASSWORD_REQUEST';
+export const CHANGE_PASSWORD_REQUEST_SUCCESS = 'CHANGE_PASSWORD_REQUEST_SUCCESS';
+export const CHANGE_PASSWORD_REQUEST_FAILURE = 'CHANGE_PASSWORD_REQUEST_FAILURE';

+ 0 - 2
src/index.js

@@ -7,8 +7,6 @@ import Router from './router'
 import reduxStore from './state'
 
 import 'bootstrap/dist/css/bootstrap.min.css';
-import $ from 'jquery';
-import Popper from 'popper.js';
 import 'bootstrap/dist/js/bootstrap.bundle.min';
 
 import './styles/_index.scss';

+ 8 - 3
src/reducers/auth/signIn.js

@@ -1,8 +1,9 @@
 import * as actionTypes from './../../constants/auth';
 import initialState from './../initialState';
 
-export default function signInReducer(state = initialState.signIn, {type, payload: data, error}) {
-    switch(type) {
+export default function signInReducer(state = initialState.signIn, {payload, type, error}) {
+
+    switch (type) { // payload.type -> type
         case actionTypes.SIGN_IN_REQUEST: {
             return {
                 ...state,
@@ -10,13 +11,17 @@ export default function signInReducer(state = initialState.signIn, {type, payloa
             }
         }
         case actionTypes.SIGN_IN_REQUEST_SUCCESS: {
+            const { user, token } = payload;
+
             return {
                 ...state,
                 isFetching: false,
-                data
+                data: user,
+                token
             }
         }
         case actionTypes.SIGN_IN_REQUEST_FAILURE: {
+
             return {
                 ...state,
                 isFetching: false,

+ 8 - 4
src/reducers/auth/signUp.js

@@ -3,26 +3,30 @@ import initialState from './../initialState';
 
 export default function signInReducer(state = initialState.signUp, {type, payload, error}) {
     switch(type) {
-        case actionTypes.SIGN_IN_REQUEST: {
+        case actionTypes.SIGN_UP_REQUEST: {
             return {
                 ...state,
                 isFetching: true
             }
         }
-        case actionTypes.SIGN_IN_REQUEST_SUCCESS: {
+        
+        case actionTypes.SIGN_UP_REQUEST_SUCCESS: {
             return {
                 ...state,
                 isFetching: false,
-                payload
+                isSuccessful: true
             }
         }
-        case actionTypes.SIGN_IN_REQUEST_FAILURE: {
+
+        case actionTypes.SIGN_UP_REQUEST_FAILURE: {
             return {
                 ...state,
                 isFetching: false,
+                isSuccessful: false,
                 error
             }
         }
+
         default: {
             return state;
         }

+ 9 - 1
src/reducers/index.js

@@ -1,9 +1,17 @@
 import { combineReducers } from 'redux';
 import { reducer as form } from 'redux-form';
 
-import signIn from './auth/signIn'
+import signIn from './auth/signIn';
+import signUp from './auth/signUp';
+
+import chageLoginReducer from './user/chageLogin';
+import changeEmailReducer from './user/changeEmail';
 
 export default combineReducers({
+
     signIn,
+    signUp,
+    chageLoginReducer,
+    changeEmailReducer,
     form
 })

+ 13 - 2
src/reducers/initialState.js

@@ -2,11 +2,22 @@ export default {
     signIn: {
         isFetching: false,
         data: null,
-        error: null
+        error: null,
+        token: null
     },
     signUp: {
+        isFetching: false,
+        isSuccessful: null,
+        error: null
+    },
+    changeLogin:{
         isFetching: false,
         data: null,
         error: null
-    }
+    },
+    changeEmail:{
+        isFetching: false,
+        data: null,
+        error: null
+    },
 }

+ 37 - 0
src/reducers/user/chageLogin.js

@@ -0,0 +1,37 @@
+import * as actionTypes from './../../constants/user';
+import initialState from './../initialState';
+
+export default function chageLoginReducer(state = initialState.changeLogin, {  type, payload }) {
+    switch (type) {
+        case actionTypes.CHANGE_LOGIN_REQUEST: {
+            console.log(payload)
+            return {
+                ...state,
+                isFetching: true,
+                payload
+            }
+        }
+        case actionTypes.CHANGE_LOGIN_REQUEST_SUCCESS: {
+            const { user:{name} } = payload;
+            console.log(name)
+
+            return {
+                ...state,
+                isFetching: false,
+                data:name
+            }
+        }
+        case actionTypes.CHANGE_LOGIN_REQUEST_FAILURE: {
+            const { error } = payload;
+
+            return {
+                ...state,
+                isFetching: false,
+                error
+            }
+        }
+        default: {
+            return state;
+        }
+    }
+}

+ 37 - 0
src/reducers/user/changeEmail.js

@@ -0,0 +1,37 @@
+import * as actionTypes from './../../constants/user';
+import initialState from './../initialState';
+
+export default function changeEmailReducer(state = initialState.changeEmail, {  type, payload }) {
+    switch (type) {
+        case actionTypes.CHANGE_EMAIL_REQUEST: {
+            console.log(payload)
+            return {
+                ...state,
+                isFetching: true,
+                payload
+            }
+        }
+        case actionTypes.CHANGE_EMAIL_REQUEST_SUCCESS: {
+            const { user:{email} } = payload;
+            console.log(email)
+
+            return {
+                ...state,
+                isFetching: false,
+                data:email
+            }
+        }
+        case actionTypes.CHANGE_EMAIL_REQUEST_FAILURE: {
+            const { error } = payload;
+
+            return {
+                ...state,
+                isFetching: false,
+                error
+            }
+        }
+        default: {
+            return state;
+        }
+    }
+}

+ 3 - 9
src/router.js

@@ -6,24 +6,18 @@ import ProtectedRoute from './components/common/protectedRoute';
 import config from './configs/routerConfig';
 
 import Header from './components/public/Header';
+import Spinner from './components/common/spinner';
 
 import { bindActionCreators } from "redux";
 
 class Router extends React.Component {
     render() {
         const { user, tokenAuth } = this.props;
-
         // TODO: add footer
         return (
             <div className="app">
                 <Header />
-                <Suspense fallback={
-                    <div class="text-center">
-                        <div class="spinner-border" role="status">
-                            <span class="sr-only">Loading...</span>
-                        </div>
-                    </div>
-                }>
+                <Suspense fallback={<Spinner />}>
                     <Switch>
                         {config.map(route =>
                             <ProtectedRoute
@@ -43,7 +37,7 @@ class Router extends React.Component {
 }
 
 const mapStateToProps = state => ({
-    user: state.user
+    user: state.signIn
 })
 // const mapDispatchToProps = dispatch => bindActionCreators({ tokenAuth }, dispatch);
 

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

@@ -5,7 +5,6 @@ import * as actionTypes from './../../constants/auth'
 import { takeEvery } from 'redux-saga/effects';
 
 export default function* () {
-    console.log('takeEvery');
     yield takeEvery(actionTypes.SIGN_IN_REQUEST, signIn)
     yield takeEvery(actionTypes.SIGN_UP_REQUEST, signUp)
 }

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

@@ -2,10 +2,10 @@ import { put, call } from 'redux-saga/effects';
 import axios from 'axios';
 
 import { SIGN_IN_URL } from './../../constants/auth';
+import storageKey from './../../utils/storageKey';
 import { signInSuccess, signInFailure } from './../../actions/auth/signIn'
 
-export default function* ({payload}) {
-    console.log('User inside the worker-saga', payload);
+export default function* ({ payload }) {
     try {
         const config = {
             headers: {
@@ -18,7 +18,8 @@ export default function* ({payload}) {
                 .then(({ data }) => data)
         )
 
-
+        //TODO: TOKEN
+        // yield call(localStorage.setItem, storageKey, user.token);
         yield put(signInSuccess(user));
     }
     catch ({ message }) {

+ 24 - 2
src/sagas/auth/signUp.js

@@ -1,3 +1,25 @@
-export default function* () {
-    
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { SIGN_UP_URL } from './../../constants/auth';
+import { signUpSuccess, signUpFailure } from './../../actions/auth/signUp';
+
+export default function* ({payload}) {
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json"
+            }
+        }
+
+        const report = yield call(() =>
+            axios.post(SIGN_UP_URL, payload, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(signUpSuccess(report));
+    }
+    catch ({ message }) {
+        yield put(signUpFailure(message));
+    }
 }

+ 3 - 1
src/sagas/index.js

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

+ 27 - 0
src/sagas/user/changeEmail.js

@@ -0,0 +1,27 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { USER_URL } from './../../constants/user';
+import { changeEmailSuccess, changeEmailFailure } from './../../actions/user/changeEmail'
+
+export default function* ({payload:{_id,email,token}}) {
+    console.log('User inside the worker-saga', _id,email,token);
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.put(`${USER_URL}${_id}`,{email:email}, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(changeEmailSuccess(user));
+    }
+    catch ({ message }) {
+        yield put(changeEmailFailure(message));
+    }
+}

+ 27 - 0
src/sagas/user/changeLogin.js

@@ -0,0 +1,27 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { USER_URL } from './../../constants/user';
+import { changeLoginSuccess, changeLoginFailure } from './../../actions/user/changelogin'
+
+export default function* ({payload:{_id,name,token}}) {
+    console.log('User inside the worker-saga', _id,name,token);
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.put(`${USER_URL}${_id}`,{name:name}, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(changeLoginSuccess(user));
+    }
+    catch ({ message }) {
+        yield put(changeLoginFailure(message));
+    }
+}

+ 28 - 0
src/sagas/user/changePassword.js

@@ -0,0 +1,28 @@
+import { put, call } from 'redux-saga/effects';
+import axios from 'axios';
+
+import { USER_URL } from './../../constants/user';
+import { changePasswordSuccess, changePasswordFailure } from './../../actions/user/changePassword'
+
+export default function* ({payload:{_id, password, confirmPassword,token}}) {
+    console.log('User inside the worker-saga', _id, password, confirmPassword, token);
+    try {
+        const config = {
+            headers: {
+                "Content-Type": "application/json",
+                "Authorization": `Bearer ${token}`
+            }
+        }
+
+        const user = yield call(() =>
+            axios.put(`${USER_URL}${_id}`,{
+                password, confirmPassword}, config)
+                .then(({ data }) => data)
+        )
+
+        yield put(changePasswordSuccess(user));
+    }
+    catch ({ message }) {
+        yield put(changePasswordFailure(message));
+    }
+}

+ 15 - 0
src/sagas/user/index.js

@@ -0,0 +1,15 @@
+import changeLogin from './changeLogin';
+import changeEmail from './changeEmail';
+import changePassword from './changePassword'
+import * as actionTypes from './../../constants/user'
+
+import { takeEvery } from 'redux-saga/effects';
+
+export default function* () {
+    yield takeEvery(actionTypes.CHANGE_LOGIN_REQUEST, changeLogin);
+    yield takeEvery(actionTypes.CHANGE_EMAIL_REQUEST, changeEmail);
+    yield takeEvery(actionTypes.CHANGE_PASSWORD_REQUEST, changePassword);
+
+
+
+}

+ 3 - 1
src/styles/_index.scss

@@ -1,3 +1,5 @@
 @import 'abstracts/variables';
+@import 'abstracts/theme';
+@import 'extended/vh';
+
 @import 'base/typography';
-@import 'base/theme';

src/styles/base/_theme.scss → src/styles/abstracts/_theme.scss


+ 14 - 0
src/styles/extended/_vh.scss

@@ -0,0 +1,14 @@
+.vh {
+    &-100 {
+        height: 100vh;
+    }
+    &-75 {
+        height: 75vh;
+    }
+    &-50 {
+        height: 50vh;
+    }
+    &-25 {
+        height: 25vh;
+    }
+}

+ 1 - 0
src/utils/storageKey.js

@@ -0,0 +1 @@
+export default 'https://test.io';