diff --git a/src/actions/login.js b/src/actions/login.js new file mode 100644 index 0000000..42852aa --- /dev/null +++ b/src/actions/login.js @@ -0,0 +1,121 @@ +import { + LOGIN_START, + LOGIN_SUCCESS, + LOGIN_FAILURE, + REGISTRATION_START, + REGISTRATION_SUCCESS, + REGISTRATION_FAILURE, + apiURL, + ALERT_SHOW, + ALERT_HIDE, +} from '../constants'; +import fetchAsync from '../utils/fetch'; +import createExpiresCookie from '../utils/create-expires-cookie'; + +const cookie = require('isomorphic-cookie'); + +const minutesOfCookieLive = 60; +export function loginStart() { + return { + type: LOGIN_START, + }; +} +export function loginSuccess(data) { + cookie.save('token', data.data.token, { + expires: createExpiresCookie(minutesOfCookieLive), + secure: false, + }); + return { + type: LOGIN_SUCCESS, + data, + }; +} +export function alertShow(text) { + return { + type: ALERT_SHOW, + text, + }; +} +export function alertHide() { + return { + type: ALERT_HIDE, + }; +} +export function alertCreator(text) { + const millisecondsToAlertDisapear = 3000; + return dispatch => { + dispatch(alertShow(text)); + setTimeout(() => { + dispatch(alertHide()); + }, millisecondsToAlertDisapear); + }; +} + +export function loginFailure(data) { + return { + type: LOGIN_FAILURE, + data, + }; +} +export function login(loginValue) { + return async dispatch => { + dispatch(loginStart()); + try { + const payload = await fetchAsync(`${apiURL}/login`, 'POST', loginValue); + if (!payload.data) { + dispatch(alertCreator(payload.message)); + return dispatch(loginFailure(payload)); + } + dispatch(alertCreator(payload.message)); + return dispatch(loginSuccess(payload)); + } catch (error) { + dispatch(alertCreator('Wow, some error appear')); + return dispatch(loginFailure(error)); + } + }; +} + +export function registrationStart() { + return { + type: REGISTRATION_START, + }; +} +export function registrationSuccess(data) { + cookie.save('token', data.data.token, { + expires: createExpiresCookie(minutesOfCookieLive), + secure: false, + }); + return { + type: REGISTRATION_SUCCESS, + data, + }; +} + +export function registrationFailure(data) { + return { + type: REGISTRATION_FAILURE, + data, + }; +} + +export function registration(regitrationValue) { + return async dispatch => { + dispatch(registrationStart()); + try { + const payload = await fetchAsync( + `${apiURL}/registration`, + 'POST', + regitrationValue, + ); + if (!payload.data) { + dispatch(alertCreator(payload.message)); + return dispatch(registrationFailure(payload)); + } + dispatch(alertCreator(payload.message)); + return dispatch(registrationSuccess(payload)); + } catch (error) { + dispatch(alertCreator('Wow, some error appear')); + return dispatch(registrationFailure(error)); + } + }; +} diff --git a/src/constants/index.js b/src/constants/index.js index 7262845..5d2aede 100644 --- a/src/constants/index.js +++ b/src/constants/index.js @@ -18,6 +18,17 @@ export const GET_ALL_MESSAGES = 'GET_ALL_MESSAGES'; export const CHAT_ADD_MESSAGE = 'CHAT_ADD_MESSAGE'; export const CHAT_MESSAGE_IS_TYPING = 'CHAT_MESSAGE_IS_TYPING'; export const CHAT_REMOVE_MESSAGE = 'CHAT_REMOVE_MESSAGE'; +// login +export const LOGIN_START = 'LOGIN_START'; +export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; +export const LOGIN_FAILURE = 'LOGIN_FAILURE'; +export const REGISTRATION_SUCCESS = 'REGISTRATION_SUCCESS'; +export const REGISTRATION_FAILURE = 'REGISTRATION_FAILURE'; +export const REGISTRATION_START = 'REGISTRATION_START'; +export const ALERT_SHOW = 'ALERT_SHOW'; +export const ALERT_HIDE = 'ALERT_HIDE'; + +// login end export const CHAT_UPDATE_MESSAGE_BY_ID = 'CHAT_UPDATE_MESSAGE_BY_ID'; export const EDIT_MESSAGE = 'EDIT_MESSAGE'; diff --git a/src/reducers/index.js b/src/reducers/index.js index 2578c57..5ccdc75 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -2,6 +2,7 @@ import { combineReducers } from 'redux'; import { reducer as formReducer } from 'redux-form'; import movementDetection from './movement-detection'; import chat from './chat'; +import login from './login'; import windowSensors from './window-sensors'; export default combineReducers({ @@ -9,4 +10,5 @@ export default combineReducers({ windowSensors, movementDetection, form: formReducer, + login, }); diff --git a/src/reducers/login.js b/src/reducers/login.js new file mode 100644 index 0000000..571c3d1 --- /dev/null +++ b/src/reducers/login.js @@ -0,0 +1,70 @@ +import { + LOGIN_START, + LOGIN_SUCCESS, + LOGIN_FAILURE, + REGISTRATION_START, + REGISTRATION_FAILURE, + REGISTRATION_SUCCESS, + ALERT_HIDE, + ALERT_SHOW, +} from '../constants'; + +const initialState = { + loading: false, + isLogedIn: false, + alert: null, +}; +export default function login(state = initialState, action) { + switch (action.type) { + case LOGIN_START: + return { + ...state, + loading: true, + }; + case LOGIN_SUCCESS: + return { + ...state, + loading: false, + ...action.data, + isLogedIn: true, + }; + case LOGIN_FAILURE: + return { + ...state, + loading: false, + ...action.data, + isLogedIn: false, + }; + case REGISTRATION_START: + return { + ...state, + loading: true, + }; + case REGISTRATION_FAILURE: + return { + ...state, + loading: false, + ...action.data, + isLogedIn: false, + }; + case REGISTRATION_SUCCESS: + return { + ...state, + loading: false, + ...action.data, + isLogedIn: true, + }; + case ALERT_HIDE: + return { + ...state, + alert: null, + }; + case ALERT_SHOW: + return { + ...state, + alert: action.text, + }; + default: + return state; + } +} diff --git a/src/routes/index.js b/src/routes/index.js index e7318f8..79de8b2 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -1,18 +1,30 @@ import invoke from 'lodash/invoke'; import nth from 'lodash/nth'; +// import cookie from 'isomorphic-cookie'; const routes = [ { action({ next }) { return next(); }, - children: [], + children: [ + { + load: () => import('./login'), + path: '/login', + }, + ], path: '', }, { async action({ next }) { // Execute each child route until one of them return the result const route = await next(); + if ( + // !cookie.load('token') + false // at this time false!!! + ) { + route.redirect = '/login'; + } // Provide default values for title, description etc. route.title = `${route.title || 'Untitled Page'}`; diff --git a/src/routes/login/Login.css b/src/routes/login/Login.css index f8cb29e..1aa894d 100644 --- a/src/routes/login/Login.css +++ b/src/routes/login/Login.css @@ -28,22 +28,13 @@ } .formContainer button { - border: none; - border-radius: 5px; - height: 25px; - background: #eee; - margin-right: 10px; - outline: none; width: 50%; align-self: center; } -.formContainer button:hover { - cursor: pointer; -} - .textLogin { color: #cecece; + margin-top: 15px; display: flex; width: 100%; justify-content: center; diff --git a/src/routes/login/Login.js b/src/routes/login/Login.js index 97776e7..c335951 100644 --- a/src/routes/login/Login.js +++ b/src/routes/login/Login.js @@ -1,70 +1,92 @@ -import React, { memo, useCallback, useState } from 'react'; +import React, { useCallback } from 'react'; +import { useSelector, useDispatch } from 'react-redux'; import useStyles from 'isomorphic-style-loader/useStyles'; +import { Field, reduxForm } from 'redux-form'; +import CustomFieldLogin from './components/CustomFieldLogin/CustomFieldLogin'; import s from './Login.css'; -import Input from './components/Input'; -import LoginButton from './components/LoginButton'; +import LoginButton from './components/LoginButton/LoginButton'; +import { login, registration, alertCreator } from '../../actions/login'; +import Alert from './components/Alert/Alert'; + +const validate = value => { + const errors = {}; + const minLengthPassword = 5; + if (!value.email) { + errors.email = 'Required'; + } else if (value.email.length < minLengthPassword) { + errors.email = `Bro, not enough characters for a valid email`; + } else if (!value.email.match(/^[\d.a-z-]+@[\da-z-]{2,}.[a-z]{2,}$/i)) { + errors.email = 'Please, check your email, it looks invalid '; + } + if (!value.password) { + errors.password = 'Required'; + } else if (value.password.length < minLengthPassword) { + errors.password = `Password must have at least 5 characters, you typed only ${value.password.length}`; + } + + return errors; +}; function Login() { + const formLoginState = useSelector(state => state.form.Login); + const formLoginValue = useSelector(state => state.form.Login.values); + const loginState = useSelector(state => state.login); + const dispatch = useDispatch(); useStyles(s); - const [inputValue, setInputValue] = useState({ - password: '', - email: '', - }); - const inputChangeHandler = useCallback(event => { - const { name } = event.target; - const { value } = event.target; - setInputValue(previous => { - return { - ...previous, - [name]: value, - }; - }); - }, []); const buttonLoginHandler = useCallback( event => { event.preventDefault(); const { name } = event.target; - switch (name) { - case 'logIn': - console.info('What we do now? :', name); - console.info('What mail of user is? :', inputValue.email); - console.info('What password is? :', inputValue.password); - break; - case 'registration': - console.info('What we do now? :', name); - console.info('What mail of user is? :', inputValue.email); - console.info('What password is? :', inputValue.password); - break; - default: - console.info('something whent wrong'); + if (formLoginState.syncErrors) { + return dispatch(alertCreator('Fields valuse are invalid')); + } + if (name === 'login') { + return dispatch(login(formLoginValue)); + } + if (name === 'registration') { + return dispatch(registration(formLoginValue)); } + return true; }, - [inputValue], + [dispatch, formLoginValue], ); + // console.info(formLoginState); return (