diff --git a/src/fireedge/package.json b/src/fireedge/package.json index a589b775369..ec55a260d76 100644 --- a/src/fireedge/package.json +++ b/src/fireedge/package.json @@ -25,6 +25,7 @@ "node": ">=12.18.2" }, "dependencies": { + "@hookform/resolvers": "0.0.6", "@material-ui/core": "^4.11.0", "@material-ui/icons": "^4.9.1", "ace-builds": "^1.4.11", diff --git a/src/fireedge/src/public/components/FormControl/ErrorHelper.js b/src/fireedge/src/public/components/FormControl/ErrorHelper.js new file mode 100644 index 00000000000..7b38a9dacf0 --- /dev/null +++ b/src/fireedge/src/public/components/FormControl/ErrorHelper.js @@ -0,0 +1,41 @@ +import React from 'react'; + +import { Box, darken, lighten, makeStyles, Typography } from '@material-ui/core'; +import { Info as InfoIcon } from '@material-ui/icons'; + +import { Translate } from 'client/components/HOC'; + +const useStyles = makeStyles(theme => { + const getColor = theme.palette.type === 'light' ? darken : lighten; + const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken; + + return { + root: { + color: theme.palette.error.dark, + display: 'flex', + alignItems: 'center' + }, + icon: { + fontSize: 16 + }, + text: { + ...theme.typography.body1, + paddingLeft: theme.spacing(1) + } + }; +}); + +const ErrorHelper = ({ label = 'Error', ...rest }) => { + const classes = useStyles(); + + return ( + + + + + + + ); +}; + +export default ErrorHelper; diff --git a/src/fireedge/src/public/components/FormControl/inputCode.js b/src/fireedge/src/public/components/FormControl/InputCode.js similarity index 100% rename from src/fireedge/src/public/components/FormControl/inputCode.js rename to src/fireedge/src/public/components/FormControl/InputCode.js diff --git a/src/fireedge/src/public/components/FormControl/submitButton.js b/src/fireedge/src/public/components/FormControl/SubmitButton.js similarity index 100% rename from src/fireedge/src/public/components/FormControl/submitButton.js rename to src/fireedge/src/public/components/FormControl/SubmitButton.js diff --git a/src/fireedge/src/public/containers/Login/Login.js b/src/fireedge/src/public/containers/Login/Login.js index efb5c15e6a7..1ae64b35366 100644 --- a/src/fireedge/src/public/containers/Login/Login.js +++ b/src/fireedge/src/public/containers/Login/Login.js @@ -23,32 +23,40 @@ import { FormControlLabel } from '@material-ui/core'; import { useForm } from 'react-hook-form'; +import { yupResolver } from '@hookform/resolvers'; import * as yup from 'yup'; import { SignIn, Username, Password, keepLoggedIn } from 'client/constants'; import { Translate, Tr } from 'client/components/HOC'; -import ButtonSubmit from 'client/components/FormControl/submitButton'; +import ButtonSubmit from 'client/components/FormControl/SubmitButton'; +import ErrorHelper from 'client/components/FormControl/ErrorHelper'; import useAuth from 'client/hooks/auth/useAuth'; import loginStyles from './styles'; function Login() { const classes = loginStyles(); - const { isLoading, login } = useAuth(); + const { isLoading, login, error } = useAuth(); - const { register, handleSubmit, errors } = useForm( - yup.object().shape({ - user: yup.string().required(), - pass: yup.string().required(), - remember: yup.boolean() - }) - ); + const { register, handleSubmit, errors } = useForm({ + reValidateMode: 'onSubmit', + resolver: yupResolver( + yup.object().shape({ + user: yup.string().required('Username is a required field'), + pass: yup.string().required('Password is a required field'), + remember: yup.boolean() + }) + ) + }); const onSubmit = dataForm => { const { remember, ...user } = dataForm; login(user, remember); }; + const userError = Boolean(errors.user || error); + const passError = Boolean(errors.pass); + return ( @@ -67,24 +75,30 @@ function Login() { fullWidth required name="user" - error={Boolean(errors.user)} - helperText={errors.user?.message} label={Tr(Username)} variant="outlined" inputRef={register} inputProps={{ 'data-cy': 'login-username' }} + error={userError} + helperText={ + userError && + } + FormHelperTextProps={{ 'data-cy': 'login-username-error' }} /> + } + FormHelperTextProps={{ 'data-cy': 'login-password-error' }} /> } label={Tr(keepLoggedIn)} diff --git a/src/fireedge/src/public/containers/Login/styles.js b/src/fireedge/src/public/containers/Login/styles.js index 882c4248615..0f57ab619fd 100644 --- a/src/fireedge/src/public/containers/Login/styles.js +++ b/src/fireedge/src/public/containers/Login/styles.js @@ -1,21 +1,31 @@ import { makeStyles } from '@material-ui/core'; -export default makeStyles(theme => ({ - root: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center' - }, - paper: { - padding: theme.spacing(3) - }, - form: { - display: 'flex', - flexDirection: 'column', - justifyContent: 'center' - }, - logo: { - width: '50%', - margin: '1.5rem auto' - } -})); +export default makeStyles(theme => { + // const getColor = theme.palette.type === 'light' ? darken : lighten; + // const getBackgroundColor = theme.palette.type === 'light' ? lighten : darken; + // color: getColor(theme.palette.error.main, 0.6), + // backgroundColor: getBackgroundColor(theme.palette.error.main, 0.9) + + return { + root: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }, + paper: { + padding: theme.spacing(3) + }, + form: { + display: 'flex', + flexDirection: 'column', + justifyContent: 'center' + }, + logo: { + width: '50%', + margin: '1.5rem auto' + }, + helper: { + animation: '1s ease-out 0s 1' + } + }; +}); diff --git a/src/fireedge/src/public/containers/TestApi/ResponseForm.js b/src/fireedge/src/public/containers/TestApi/ResponseForm.js index 8eee39f1142..1725939ff89 100644 --- a/src/fireedge/src/public/containers/TestApi/ResponseForm.js +++ b/src/fireedge/src/public/containers/TestApi/ResponseForm.js @@ -11,9 +11,9 @@ import { Checkbox } from '@material-ui/core'; -import ButtonSubmit from '../../components/FormControl/submitButton'; -import { requestData } from '../../utils'; -import { from as resourceFrom } from '../../../utils/constants/defaults'; +import ButtonSubmit from 'client/components/FormControl/SubmitButton'; +import { requestData } from 'client/utils'; +import { from as resourceFrom } from 'server/utils/constants/defaults'; const getQueries = params => Object.entries(params) diff --git a/src/fireedge/src/public/containers/TestApi/index.js b/src/fireedge/src/public/containers/TestApi/index.js index 21b1f1b4bee..9f6f2bd67ff 100644 --- a/src/fireedge/src/public/containers/TestApi/index.js +++ b/src/fireedge/src/public/containers/TestApi/index.js @@ -15,10 +15,10 @@ import React, { useState, useMemo } from 'react'; import { TextField, Grid, MenuItem } from '@material-ui/core'; -import Commands from '../../../utils/constants/commands'; -import { Translate } from '../../components/HOC'; -import ResponseForm from './ResponseForm'; -import InputCode from '../../components/FormControl/inputCode'; +import Commands from 'server/utils/constants/commands'; +import { Translate } from 'client/components/HOC'; +import InputCode from 'client/components/FormControl/InputCode'; +import ResponseForm from 'client/containers/TestApi/ResponseForm'; const TestApi = () => { const [name, setName] = useState('acl.addrule'); diff --git a/src/fireedge/src/public/hooks/auth/useAuth.js b/src/fireedge/src/public/hooks/auth/useAuth.js index c488e5cf044..4329811f07d 100644 --- a/src/fireedge/src/public/hooks/auth/useAuth.js +++ b/src/fireedge/src/public/hooks/auth/useAuth.js @@ -8,7 +8,7 @@ import * as servicesAuth from 'client/services/auth'; import * as actions from 'client/actions/user'; export default function useAuth() { - const { isLoading, jwt, user: authUser, firstRender } = useSelector( + const { isLoading, jwt, user: authUser, firstRender, error } = useSelector( state => state?.Authenticated, shallowEqual ); @@ -31,9 +31,9 @@ export default function useAuth() { storage(jwtName, data?.token, remember); dispatch(actions.loginSuccess(data?.token)); }) - .catch(message => { + .catch(res => { removeStoreData(jwtName); - dispatch(actions.loginFailure(message)); + dispatch(actions.loginFailure('Unauthenticated')); }); }, [baseURL, jwtName] @@ -61,9 +61,9 @@ export default function useAuth() { logout, getAuthUser, authUser, - jwt, isLogged: Boolean(jwt), isLoading, - firstRender + firstRender, + error }; } diff --git a/src/fireedge/src/public/reducers/auth.js b/src/fireedge/src/public/reducers/auth.js index 182ea4679a9..ce2dc18e7f0 100644 --- a/src/fireedge/src/public/reducers/auth.js +++ b/src/fireedge/src/public/reducers/auth.js @@ -15,7 +15,6 @@ const actions = require('client/actions/user'); const { jwtName } = require('client/constants'); -const { console } = require('window-or-global'); const jwt = typeof window !== 'undefined' @@ -36,6 +35,7 @@ const authentication = (state = initial, action) => { switch (action.type) { case actions.LOGIN_REQUEST: return { + ...state, isLoading: true }; case actions.LOGIN_SUCCESS: diff --git a/src/fireedge/src/public/services/auth.js b/src/fireedge/src/public/services/auth.js index 144916fa106..a9262143d9e 100644 --- a/src/fireedge/src/public/services/auth.js +++ b/src/fireedge/src/public/services/auth.js @@ -10,14 +10,14 @@ export const login = (user, baseURL = '') => baseURL, error: console.error }).then(res => { - if (!res?.id || res?.id !== httpCodes.ok.id) throw new Error(res?.message); + if (!res?.id || res?.id !== httpCodes.ok.id) throw new Error(res); return res; }); export const getUser = () => requestData(endpointsRoutes.userInfo).then(res => { - if (!res?.id || res?.id !== httpCodes.ok.id) throw new Error(res?.message); + if (!res?.id || res?.id !== httpCodes.ok.id) throw new Error(res); return res; });