Feature - Login integration (#7)

* Added: formik and validation schema

* Added: Validation schema

* Added: logout test integration

* Added: Enter key to submit

* Added: incorrect password error message

* Removed: logger

* Updated: logout initial state

Co-authored-by: Llewellyn D'souza <lledsouza2209@gmail.com>
Jira ticket ref: WMS-27
This commit is contained in:
bluestreamlds
2022-01-20 10:08:50 +05:30
committed by GitHub
parent f8f47ae983
commit f7a0bf64f2
5 changed files with 97 additions and 295 deletions

View File

@@ -1,5 +1,3 @@
import { useState } from 'react';
// react-router-dom components // react-router-dom components
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
@@ -21,23 +19,40 @@ import { API } from 'constant';
// Image // Image
import bgImage from 'assets/images/illustrations/illustration-reset.jpg'; import bgImage from 'assets/images/illustrations/illustration-reset.jpg';
import { useFormik } from 'formik';
import schema from 'services/ValidationServices';
import { useState } from 'react';
function LoginScreen() { function LoginScreen() {
const [rememberMe, setRememberMe] = useState(false);
const handleSetRememberMe = () => setRememberMe(!rememberMe);
const dispatch = useDispatch(); const dispatch = useDispatch();
const onPressLogin = () => { const [errorMessage, setErrorMessage] = useState(null);
const formik = useFormik({
initialValues: {
email: '',
password: '',
rememberMe: true
},
validationSchema: schema.login,
onSubmit: (values, { resetForm, setSubmitting }) => {
const onFailedLogin = (errorMessage) => {
resetForm();
setSubmitting(false);
setErrorMessage(errorMessage);
};
dispatch( dispatch(
AuthActions.loginRequest({ AuthActions.loginRequest({
loader: 'login-request', loader: 'login-request',
slug: API.LOGIN_USER, slug: API.LOGIN_USER,
method: 'post', method: 'post',
data: { email: 'satizkris+1@gmail.com', password: 'mypassword' } data: { email: values.email, password: values.password },
onFailedLogin
// data: { email: 'satizkris+1@gmail.com', password: 'mypassword' }
}) })
); );
}; }
});
return ( return (
<AuthLayout <AuthLayout
@@ -45,27 +60,60 @@ function LoginScreen() {
description="Enter your email and password to sign in" description="Enter your email and password to sign in"
illustration={bgImage} illustration={bgImage}
> >
<MDBox component="form" role="form"> <MDBox component="form" role="form" onSubmit={formik.handleSubmit}>
<MDBox mb={2}> <MDBox mb={2}>
<MDInput fullWidth type="email" label="Email" /> <MDInput
fullWidth
name="email"
type="email"
label="Email"
value={formik.values.email}
error={formik.touched.email && Boolean(formik.errors.email)}
helperText={formik.touched.email && formik.errors.email}
onChange={formik.handleChange}
/>
</MDBox> </MDBox>
<MDBox mb={2}> <MDBox mb={2}>
<MDInput fullWidth type="password" label="Password" /> <MDInput
fullWidth
type="password"
name="password"
label="Password"
value={formik.values.password}
error={formik.touched.password && Boolean(formik.errors.password)}
helperText={formik.touched.password && formik.errors.password}
onChange={formik.handleChange}
/>
</MDBox> </MDBox>
<MDBox display="flex" alignItems="center" ml={-1}> <MDBox display="flex" alignItems="center" ml={-1}>
<Switch checked={rememberMe} onChange={handleSetRememberMe} /> <Switch
name="rememberMe"
checked={formik.values.rememberMe}
onChange={formik.handleChange}
/>
<MDTypography <MDTypography
variant="button" variant="button"
fontWeight="regular" fontWeight="regular"
color="text" color="text"
sx={{ cursor: 'pointer', userSelect: 'none', ml: -1 }} sx={{ cursor: 'pointer', userSelect: 'none', ml: -1 }}
onClick={handleSetRememberMe} onClick={formik.handleChange}
> >
&nbsp;&nbsp;Remember me &nbsp;&nbsp;Remember me
</MDTypography> </MDTypography>
</MDBox> </MDBox>
<MDBox mt={4} mb={1}> <MDTypography mb={2} fontSize={14} textAlign="center" color="error">
<MDButton fullWidth variant="gradient" color="info" size="large" onClick={onPressLogin}> {errorMessage ? errorMessage : ''}
</MDTypography>
<MDBox mt={1} mb={1}>
<MDButton
fullWidth
variant="gradient"
color="info"
size="large"
type="submit"
disabled={formik.isSubmitting}
onClick={formik.handleSubmit}
>
sign in sign in
</MDButton> </MDButton>
</MDBox> </MDBox>

View File

@@ -1,15 +1,20 @@
import MDBox from 'components/MDBox'; import { useDispatch } from 'react-redux';
import DashboardLayout from 'layouts/DashboardLayout'; import MDBox from 'components/MDBox';
import DashboardNavbar from 'components/DashboardNavbar'; import DashboardNavbar from 'components/DashboardNavbar';
import Footer from 'components/Footer'; import Footer from 'components/Footer';
import DashboardLayout from 'layouts/DashboardLayout';
import AuthActions from 'redux/AuthRedux';
function DashboardScreen() { function DashboardScreen() {
const dispatch = useDispatch();
const handleLogout = () => dispatch(AuthActions.logout());
return ( return (
<DashboardLayout> <DashboardLayout>
<DashboardNavbar /> <DashboardNavbar />
<MDBox py={3}> <MDBox py={3}>
<h1>Hello Dashboard</h1> <h1>Hello Dashboard</h1>
<button onClick={handleLogout}>Logout</button>
</MDBox> </MDBox>
<Footer /> <Footer />
</DashboardLayout> </DashboardLayout>

View File

@@ -49,9 +49,12 @@ export const onLoginFailure = (state, { error }) =>
error: { ...state.error, [error?.loader]: error?.error } error: { ...state.error, [error?.loader]: error?.error }
}); });
export const onLogout = () => INITIAL_STATE;
/* ------------- Hookup Reducers To Types ------------- */ /* ------------- Hookup Reducers To Types ------------- */
export const authReducer = createReducer(INITIAL_STATE, { export const authReducer = createReducer(INITIAL_STATE, {
[Types.LOGIN_REQUEST]: onLoginRequest, [Types.LOGIN_REQUEST]: onLoginRequest,
[Types.LOGIN_SUCCESS]: onLoginSuccess, [Types.LOGIN_SUCCESS]: onLoginSuccess,
[Types.LOGIN_FAILURE]: onLoginFailure [Types.LOGIN_FAILURE]: onLoginFailure,
[Types.LOGOUT]: onLogout
}); });

View File

@@ -23,6 +23,7 @@ export function* onRequestLogin({ payload }) {
}) })
); );
} else { } else {
payload.onFailedLogin(response.data.error);
yield put( yield put(
AuthActions.loginFailure({ AuthActions.loginFailure({
loader: payload?.loader, loader: payload?.loader,

View File

@@ -1,277 +1,22 @@
import * as Yup from 'yup'; import * as Yup from 'yup';
import { Strings } from '../constants';
const PASSWORD_REGEX = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*./-]).{8,}$/; // const PASSWORD_REGEX = /^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$%^&*./-]).{8,}$/;
// eslint-disable-next-line no-useless-escape // // eslint-disable-next-line no-useless-escape
const emailRegex = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; // has been disabled because we need escape characters // const emailRegex = /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/; // has been disabled because we need escape characters
const MOBILE_REG = /^[0-9]{10}$/; // Change this regex based on requirement // const MOBILE_REG = /^[0-9]{10}$/; // Change this regex based on requirement
const NAME_REG = /^[-a-zA-Z-()]+(\s+[-a-zA-Z-()]+)*$/; // const NAME_REG = /^[-a-zA-Z-()]+(\s+[-a-zA-Z-()]+)*$/;
const WEBSITE_REG = // const WEBSITE_REG =
/(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g; // /(http(s)?:\/\/.)?(www\.)?[-a-zA-Z0-9@:%._+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_+.~#?&//=]*)/g;
const HASHTAG = /^[a-z0-9\-&#\s]+$/i; // const HASHTAG = /^[a-z0-9\-&#\s]+$/i;
const schema = { const schema = {
login: Yup.object({ login: Yup.object({
email: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail), email: Yup.string('Enter your email')
password: Yup.string().required(Strings.emptyPassword) .email('Enter a valid email')
}), .required('Email is required'),
register: Yup.object({ password: Yup.string('Enter your password')
firstname: Yup.string() .min(8, 'Password should be of minimum 8 characters length')
.min(2, Strings.validName) .required('Password is required')
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyFirstName),
lastname: Yup.string()
.max(75, Strings.inValidName)
.min(2, Strings.validName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyLastName),
email: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail),
mobile_no: Yup.string().min(14, Strings.invalidMobileNumber).required(Strings.emptyMobile_no),
password: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword)
}),
forgotPassword: Yup.object({
emailOrPhone: Yup.string(Strings.errorEmailPhone)
.required(Strings.errorEmailPhone)
.test('test-name', 'Enter Valid Phone/Email', (value) => {
const isValidEmail = emailRegex.test(value);
const isValidPhone = MOBILE_REG.test(value);
if (!isValidEmail && !isValidPhone) {
return false;
}
return true;
})
}),
resetPassword: Yup.object({
newPassword: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword),
confirmPassword: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword)
}),
addCompany: Yup.object({
companyName: Yup.string()
.trim(Strings.extraSpace)
.strict()
.min(2, Strings.validName)
.max(150, Strings.max150)
.required(Strings.emptyCompanyName),
companyType: Yup.number().strict().required(Strings.emptyCompanyType),
companyWebsite: Yup.string()
.required(Strings.emptywebsite)
.matches(WEBSITE_REG, Strings.validCompanyWebSite)
.max(150, Strings.max150)
}),
editProfile: Yup.object({
firstname: Yup.string()
.min(2, Strings.validName)
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyFirstName),
lastname: Yup.string()
.min(2, Strings.validName)
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyLastName),
email: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail),
mobile_no: Yup.string()
.min(10, Strings.invalidMobileNumber)
.max(14, Strings.invalidMobileNumber)
.required(Strings.emptyMobile_no),
company_name: Yup.string()
.trim(Strings.extraSpace)
.strict()
.min(2, Strings.validName)
.max(150, Strings.max150)
.required(Strings.emptyCompanyName),
company_website: Yup.string()
.required(Strings.emptywebsite)
.max(150, Strings.max150)
.matches(WEBSITE_REG, Strings.validCompanyWebSite),
tagline: Yup.string().trim(Strings.extraSpace).strict().nullable().max(75, Strings.max75),
interest: Yup.string().trim(Strings.extraSpace).strict().max(150, Strings.max150)
}),
directditProfile: Yup.object({
firstname: Yup.string()
.min(2, Strings.validName)
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyFirstName),
lastname: Yup.string()
.min(2, Strings.validName)
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyLastName),
email: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail),
mobile_no: Yup.string()
.min(10, Strings.invalidMobileNumber)
.max(14, Strings.invalidMobileNumber)
.required(Strings.emptyMobile_no),
tagline: Yup.string().trim(Strings.extraSpace).strict().nullable().max(75, Strings.max75),
interest: Yup.string().trim(Strings.extraSpace).strict().max(150, Strings.max150)
}),
changePassword: Yup.object({
currentPassword: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword),
newPassword: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword),
confirmPassword: Yup.string()
.matches(PASSWORD_REGEX, Strings.invalidPassword)
.required(Strings.emptyPassword)
}),
editEducation: Yup.object({
school: Yup.string()
.trim(Strings.extraSpace)
.strict()
.min(2, Strings.validName)
.max(250, Strings.maxSchool)
.required(Strings.emptySchool),
degree: Yup.string()
.trim(Strings.extraSpace)
.strict()
.min(2, Strings.validName)
.max(100, Strings.max100)
.required(Strings.emptyDegree),
field_of_study: Yup.string()
.trim(Strings.extraSpace)
.strict()
.min(2, Strings.validName)
.max(100, Strings.max100)
.required(Strings.emptyField),
start_year: Yup.string().required(Strings.emptyStartYear),
end_year: Yup.string().required(Strings.emptyEndYear)
}),
editEmploy: Yup.object({
hospital_name: Yup.string()
.min(2, Strings.validName)
.max(100, Strings.max100)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyCompany),
location: Yup.string().required(Strings.emptyLocation)
}),
needHelp: Yup.object({
subjectTextInput: Yup.string().required(Strings.inValidSubject).max(150, Strings.max150),
subjectDescriptionTextInput: Yup.string()
.required(Strings.inValidSubject)
.max(1000, Strings.max1000)
}),
editAbout: Yup.object({
about: Yup.string()
.trim(Strings.extraSpace)
.strict()
.max(500, Strings.validAbout)
.required(Strings.inValidSubject)
}),
createPost: Yup.object({
description: Yup.string()
.max(15000, Strings.validateDescriptionChar)
.required(Strings.emptyDesc),
hashtag: Yup.string().matches(HASHTAG, Strings.hashtagErr).max(1000, Strings.hashtagLimitErr),
link: Yup.string()
.matches(WEBSITE_REG, Strings.urlError)
.max(15000, Strings.validateDescriptionChar)
}),
createPoll: Yup.object({
description: Yup.string()
.max(15000, Strings.validateDescriptionChar)
.required(Strings.emptyDesc),
link: Yup.string()
.matches(WEBSITE_REG, Strings.urlError)
.max(15000, Strings.validateDescriptionChar),
question: Yup.string().max(70, Strings.validateQueChar).required(Strings.emptyQue),
optionOne: Yup.string().max(50, Strings.validateAnsChar).required(Strings.emptyAns1),
optionTwo: Yup.string().max(50, Strings.validateAnsChar).required(Strings.emptyAns2),
Option3: Yup.string().max(50, Strings.validateAnsChar),
Option4: Yup.string().max(50, Strings.validateAnsChar),
Option5: Yup.string().max(50, Strings.validateAnsChar)
}),
shareStatus: Yup.object({
shareStatus: Yup.string().max(15000, Strings.validateDescriptionChar)
}),
createEvent: Yup.object({
eventName: Yup.string().required(Strings.eventNameError).max(75),
location: Yup.string().required(Strings.emptyLocation),
venue: Yup.string().required(Strings.emptyVenue).max(150),
timezone: Yup.object().required(Strings.emptyTimezone),
description: Yup.string().required(Strings.emptyDesc).max(1000)
}),
onlineEvent: Yup.object({
eventName: Yup.string().required(Strings.eventNameError).max(75),
broadcastLink: Yup.string()
.matches(WEBSITE_REG, Strings.urlError)
.max(15000, Strings.validateDescriptionChar)
.required(Strings.emptyLink),
timezone: Yup.object().required(Strings.emptyTimezone),
description: Yup.string().required(Strings.emptyDesc).max(1000)
}),
orthoEvent: Yup.object({
eventName: Yup.string().required(Strings.eventNameError).max(75),
timezone: Yup.object().required(Strings.emptyTimezone),
description: Yup.string().required(Strings.emptyDesc).max(1000)
}),
createLivePost: Yup.object({
type: Yup.object().required(Strings.liveStreamTypeValidation),
privacy: Yup.object().required(Strings.liveStreamPrivacyValidation),
group: Yup.object().when('privacy', (privacy) => {
if (privacy?.label?.toLowerCase()?.trim() === Strings.group?.toLowerCase()?.trim()) {
return Yup.object().required(Strings.liveStreamGroupValidation);
}
}),
title: Yup.string().required(Strings.liveStreamTitleValidation).max(100, Strings.max100),
description: Yup.string().max(15000, Strings.max15000),
allow_comments: Yup.bool()
}),
createGroup: Yup.object({
groupName: Yup.string().required(Strings.groupNameErr).max(70, Strings.groupNameCharErr),
description: Yup.string()
.max(15000, Strings.validateDescriptionChar)
.required(Strings.groupDescErr),
groupType: Yup.string().required(Strings.groupTypeErr),
groupAccess: Yup.string().required(Strings.groupAccessErr),
speciality_ids: Yup.array().required(Strings.selectSpecialty)
}),
addEditEducation: Yup.object({
selectedTyped: Yup.string().required(Strings.educationSelectSchool).max(250, Strings.maxSchool)
}),
addEditEmployer: Yup.object({
selectedHospital: Yup.string()
.required(Strings.employerSelectHospital)
.max(250, Strings.maxSchool)
/* @COMMENTED for future scope */
/* selectedLocation: Yup.string()
.required(Strings.emptyLocation)
.max(250, Strings.maxSchool) */
}),
createPage: Yup.object({
companyPageName: Yup.string()
.required(Strings.companyNameErr)
.max(100, Strings.companyNamelimitErr),
publicUrl: Yup.string().required(Strings.publicUrlErr).max(50, Strings.publicUrllimitErr),
website: Yup.string()
.required(Strings.emptywebsite)
.matches(WEBSITE_REG, Strings.validCompanyWebSite)
.max(150, Strings.max150),
companyType: Yup.string().required(Strings.emptyCompanyType),
companySize: Yup.string().required(Strings.companySizeErr),
tagline: Yup.string().max(100, Strings.companyNamelimitErr)
}),
inviteUsers: Yup.object({
emailId: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail)
}),
checkoutCard: Yup.object({
name: Yup.string()
.min(2, Strings.validName)
.max(75, Strings.inValidName)
.matches(NAME_REG, Strings.valid)
.required(Strings.emptyName),
email: Yup.string().email(Strings.invalidEmail).required(Strings.emptyEmail),
phone: Yup.string().min(14, Strings.invalidMobileNumber).required(Strings.emptyMobile_no),
card: Yup.object()
}) })
}; };