diff --git a/src/App.tsx b/src/App.tsx index d44aa52b0f..bae62433fe 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,7 +23,6 @@ import MemberDetail from 'screens/MemberDetail/MemberDetail'; import Loader from 'components/Loader/Loader'; // User Portal Components -import UserLoginPage from 'screens/UserPortal/UserLoginPage/UserLoginPage'; import Organizations from 'screens/UserPortal/Organizations/Organizations'; import Home from 'screens/UserPortal/Home/Home'; import People from 'screens/UserPortal/People/People'; @@ -97,7 +96,7 @@ function app(): JSX.Element { return ( <> - + } /> @@ -115,7 +114,7 @@ function app(): JSX.Element { {/* User Portal Routes */} - + { - + @@ -137,7 +137,7 @@ describe('Talawa-API server fetch check', () => { - + @@ -158,7 +158,7 @@ describe('Testing Login Page Screen', () => { - + @@ -185,7 +185,7 @@ describe('Testing Login Page Screen', () => { - + @@ -230,7 +230,7 @@ describe('Testing Login Page Screen', () => { - + @@ -274,7 +274,7 @@ describe('Testing Login Page Screen', () => { - + @@ -317,7 +317,7 @@ describe('Testing Login Page Screen', () => { - + @@ -360,7 +360,7 @@ describe('Testing Login Page Screen', () => { - + @@ -400,7 +400,7 @@ describe('Testing Login Page Screen', () => { - + @@ -427,7 +427,7 @@ describe('Testing Login Page Screen', () => { - + @@ -453,7 +453,7 @@ describe('Testing Login Page Screen', () => { - + @@ -482,7 +482,7 @@ describe('Testing Login Page Screen', () => { - + @@ -513,7 +513,7 @@ describe('Testing Login Page Screen', () => { - + @@ -544,7 +544,7 @@ describe('Testing Login Page Screen', () => { - + @@ -565,7 +565,7 @@ describe('Testing Login Page Screen', () => { - + @@ -594,7 +594,7 @@ describe('Testing Login Page Screen', () => { - + @@ -623,7 +623,7 @@ describe('Testing Login Page Screen', () => { - + @@ -652,7 +652,7 @@ describe('Testing Login Page Screen', () => { - + diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index 2390731821..e83c9f4719 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -39,8 +39,11 @@ import Loader from 'components/Loader/Loader'; import { errorHandler } from 'utils/errorHandler'; import styles from './LoginPage.module.css'; import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; +interface InterfaceComponentProps { + role: string; +} -function loginPage(): JSX.Element { +function loginPage({ role = 'user' }: InterfaceComponentProps): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'loginPage' }); const history = useHistory(); @@ -113,7 +116,7 @@ function loginPage(): JSX.Element { useEffect(() => { const isLoggedIn = localStorage.getItem('IsLoggedIn'); if (isLoggedIn == 'TRUE') { - history.push('/orglist'); + history.push(role === 'admin' ? '/orglist' : '/user/organizations'); } setComponentLoader(false); }, []); @@ -164,6 +167,17 @@ function loginPage(): JSX.Element { } }; + const validatePassword = (password: string): boolean => { + const lengthCheck = new RegExp('^.{6,}$'); + return ( + lengthCheck.test(password) && + passwordValidationRegExp.lowercaseCharRegExp.test(password) && + passwordValidationRegExp.uppercaseCharRegExp.test(password) && + passwordValidationRegExp.numericalValueRegExp.test(password) && + passwordValidationRegExp.specialCharRegExp.test(password) + ); + }; + const signupLink = async (e: ChangeEvent): Promise => { e.preventDefault(); @@ -182,17 +196,6 @@ function loginPage(): JSX.Element { const isValidatedString = (value: string): boolean => /^[a-zA-Z]+$/.test(value); - const validatePassword = (password: string): boolean => { - const lengthCheck = new RegExp('^.{6,}$'); - return ( - lengthCheck.test(password) && - passwordValidationRegExp.lowercaseCharRegExp.test(password) && - passwordValidationRegExp.uppercaseCharRegExp.test(password) && - passwordValidationRegExp.numericalValueRegExp.test(password) && - passwordValidationRegExp.specialCharRegExp.test(password) - ); - }; - if ( isValidatedString(signfirstName) && isValidatedString(signlastName) && @@ -216,9 +219,11 @@ function loginPage(): JSX.Element { /* istanbul ignore next */ if (signUpData) { toast.success( - 'Successfully Registered. Please wait until you will be approved.' + role === 'admin' + ? 'Successfully Registered. Please wait until you will be approved.' + : 'Successfully registered. Please wait for admin to approve your request.' ); - + setShowTab('LOGIN'); setSignFormState({ signfirstName: '', signlastName: '', @@ -226,6 +231,12 @@ function loginPage(): JSX.Element { signPassword: '', cPassword: '', }); + setShowAlert({ + lowercaseChar: true, + uppercaseChar: true, + numericValue: true, + specialChar: true, + }); } } catch (error: any) { /* istanbul ignore next */ @@ -262,6 +273,11 @@ function loginPage(): JSX.Element { toast.error(t('Please_check_the_captcha')); return; } + /* istanbul ignore next */ + if (!validatePassword(formState.password)) { + toast.warn(t('password_invalid')); + return; + } try { const { data: loginData } = await login({ @@ -273,21 +289,29 @@ function loginPage(): JSX.Element { /* istanbul ignore next */ if (loginData) { - if ( - loginData.login.user.userType === 'SUPERADMIN' || - (loginData.login.user.userType === 'ADMIN' && - loginData.login.user.adminApproved === true) - ) { + if (role === 'admin') { + if ( + loginData.login.user.userType === 'SUPERADMIN' || + (loginData.login.user.userType === 'ADMIN' && + loginData.login.user.adminApproved === true) + ) { + localStorage.setItem('token', loginData.login.accessToken); + localStorage.setItem('refreshToken', loginData.login.refreshToken); + localStorage.setItem('id', loginData.login.user._id); + localStorage.setItem('UserType', loginData.login.user.userType); + localStorage.setItem('IsLoggedIn', 'TRUE'); + } else { + toast.warn(t('notAuthorised')); + } + } else { localStorage.setItem('token', loginData.login.accessToken); + localStorage.setItem('userId', loginData.login.user._id); localStorage.setItem('refreshToken', loginData.login.refreshToken); - localStorage.setItem('id', loginData.login.user._id); localStorage.setItem('IsLoggedIn', 'TRUE'); - localStorage.setItem('UserType', loginData.login.user.userType); - if (localStorage.getItem('IsLoggedIn') == 'TRUE') { - history.push('/orglist'); - } - } else { - toast.warn(t('notAuthorised')); + navigator.clipboard.writeText(''); + } + if (localStorage.getItem('IsLoggedIn') == 'TRUE') { + history.push(role === 'admin' ? '/orglist' : '/user/organizations'); } } else { toast.warn(t('notFound')); diff --git a/src/screens/UserPortal/UserLoginPage/UserLoginPage.test.tsx b/src/screens/LoginPage/LoginPageUser.test.tsx similarity index 88% rename from src/screens/UserPortal/UserLoginPage/UserLoginPage.test.tsx rename to src/screens/LoginPage/LoginPageUser.test.tsx index 4daa344cfd..5ed97de503 100644 --- a/src/screens/UserPortal/UserLoginPage/UserLoginPage.test.tsx +++ b/src/screens/LoginPage/LoginPageUser.test.tsx @@ -8,7 +8,7 @@ import { I18nextProvider } from 'react-i18next'; import 'jest-localstorage-mock'; import 'jest-location-mock'; import { StaticMockLink } from 'utils/StaticMockLink'; -import LoginPage from './UserLoginPage'; +import LoginPage from './LoginPage'; import { LOGIN_MUTATION, RECAPTCHA_MUTATION, @@ -116,7 +116,7 @@ describe('Talawa-API server fetch check', () => { - + @@ -137,7 +137,7 @@ describe('Talawa-API server fetch check', () => { - + @@ -158,7 +158,7 @@ describe('Testing Login Page Screen', () => { - + @@ -167,7 +167,7 @@ describe('Testing Login Page Screen', () => { await wait(); - expect(screen.getByText(/User Login/i)).toBeInTheDocument(); + expect(screen.getByText(/Admin/i)).toBeInTheDocument(); expect(window.location).toBeAt('/user/organizations'); }); @@ -176,8 +176,8 @@ describe('Testing Login Page Screen', () => { firstName: 'John', lastName: 'Doe', email: 'johndoe@gmail.com', - password: 'johndoe', - confirmPassword: 'johndoe', + password: 'John@123', + confirmPassword: 'John@123', }; render( @@ -185,7 +185,7 @@ describe('Testing Login Page Screen', () => { - + @@ -216,13 +216,57 @@ describe('Testing Login Page Screen', () => { userEvent.click(screen.getByTestId('registrationBtn')); }); + test('Testing registration functionality when all inputs are invalid', async () => { + const formData = { + firstName: '1234', + lastName: '8890', + email: 'j@l.co', + password: 'john@123', + confirmPassword: 'john@123', + }; + + render( + + + + + + + + + + ); + + await wait(); + + userEvent.click(screen.getByTestId(/goToRegisterPortion/i)); + + await wait(); + + userEvent.type( + screen.getByPlaceholderText(/First Name/i), + formData.firstName + ); + userEvent.type( + screen.getByPlaceholderText(/Last name/i), + formData.lastName + ); + userEvent.type(screen.getByTestId(/signInEmail/i), formData.email); + userEvent.type(screen.getByPlaceholderText('Password'), formData.password); + userEvent.type( + screen.getByPlaceholderText('Confirm Password'), + formData.confirmPassword + ); + userEvent.click(screen.getByTestId('registrationBtn')); + }); + test('Testing registration functionality, when password and confirm password is not same', async () => { const formData = { firstName: 'John', lastName: 'Doe', email: 'johndoe@gmail.com', - password: 'johndoe', - confirmPassword: 'doeJohn', + password: 'johnDoe@1', + confirmPassword: 'doeJohn@2', }; render( @@ -230,7 +274,7 @@ describe('Testing Login Page Screen', () => { - + @@ -273,7 +317,7 @@ describe('Testing Login Page Screen', () => { - + @@ -316,7 +360,7 @@ describe('Testing Login Page Screen', () => { - + @@ -356,7 +400,7 @@ describe('Testing Login Page Screen', () => { - + @@ -383,7 +427,7 @@ describe('Testing Login Page Screen', () => { - + @@ -409,7 +453,7 @@ describe('Testing Login Page Screen', () => { - + @@ -438,7 +482,7 @@ describe('Testing Login Page Screen', () => { - + @@ -469,7 +513,7 @@ describe('Testing Login Page Screen', () => { - + @@ -500,7 +544,7 @@ describe('Testing Login Page Screen', () => { - + @@ -521,7 +565,7 @@ describe('Testing Login Page Screen', () => { - + @@ -550,7 +594,7 @@ describe('Testing Login Page Screen', () => { - + @@ -579,7 +623,7 @@ describe('Testing Login Page Screen', () => { - + @@ -608,7 +652,7 @@ describe('Testing Login Page Screen', () => { - + diff --git a/src/screens/UserPortal/UserLoginPage/UserLoginPage.module.css b/src/screens/UserPortal/UserLoginPage/UserLoginPage.module.css deleted file mode 100644 index 413df8cecd..0000000000 --- a/src/screens/UserPortal/UserLoginPage/UserLoginPage.module.css +++ /dev/null @@ -1,208 +0,0 @@ -.login_background { - min-height: 100vh; -} - -.row .left_portion { - display: flex; - justify-content: center; - align-items: center; - flex-direction: column; - height: 100vh; -} - -.row .left_portion .inner .palisadoes_logo { - width: 600px; - height: auto; -} - -.row .right_portion { - min-height: 100vh; - position: relative; - overflow-y: scroll; - display: flex; - flex-direction: column; - justify-content: center; - padding: 1rem 2.5rem; - background: var(--bs-white); -} - -.row .right_portion::-webkit-scrollbar { - display: none; -} - -.row .right_portion .langChangeBtn { - margin: 0; - position: absolute; - top: 1rem; - left: 1rem; -} - -.langChangeBtnStyle { - width: 7.5rem; - height: 2.2rem; - padding: 0; -} - -.row .right_portion .talawa_logo { - height: 5rem; - width: 5rem; - display: block; - margin: 1.5rem auto 1rem; - -webkit-animation: zoomIn 0.3s ease-in-out; - animation: zoomIn 0.3s ease-in-out; -} - -.row .orText { - display: block; - position: absolute; - top: calc(-0.7rem - 0.5rem); - left: calc(50% - 2.6rem); - margin: 0 auto; - padding: 0.5rem 2rem; - z-index: 100; - background: var(--bs-white); - color: var(--bs-secondary); -} - -@media (max-width: 992px) { - .row .left_portion { - padding: 0 2rem; - } - - .row .left_portion .inner .palisadoes_logo { - width: 100%; - } -} - -@media (max-width: 769px) { - .row { - flex-direction: column-reverse; - } - - .row .right_portion, - .row .left_portion { - height: unset; - } - - .row .right_portion { - min-height: 100vh; - overflow-y: unset; - } - - .row .left_portion .inner { - display: flex; - justify-content: center; - } - - .row .left_portion .inner .palisadoes_logo { - height: 70px; - width: unset; - position: absolute; - margin: 0.5rem; - top: 0; - right: 0; - z-index: 100; - } - - .row .left_portion .inner p { - margin-bottom: 0; - padding: 1rem; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -@media (max-width: 577px) { - .row .right_portion { - padding: 1rem 1rem 0 1rem; - } - - .row .right_portion .langChangeBtn { - position: absolute; - margin: 1rem; - left: 0; - top: 0; - } - - .marginTopForReg { - margin-top: 4rem !important; - } - - .row .right_portion .talawa_logo { - height: 120px; - margin: 0 auto 2rem auto; - } - - .socialIcons { - margin-bottom: 1rem; - } -} - -.active_tab { - -webkit-animation: fadeIn 0.3s ease-in-out; - animation: fadeIn 0.3s ease-in-out; -} - -@-webkit-keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@keyframes zoomIn { - 0% { - opacity: 0; - -webkit-transform: scale(0.5); - transform: scale(0.5); - } - - 100% { - opacity: 1; - -webkit-transform: scale(1); - transform: scale(1); - } -} - -@-webkit-keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -@keyframes fadeIn { - 0% { - opacity: 0; - -webkit-transform: translateY(2rem); - transform: translateY(2rem); - } - - 100% { - opacity: 1; - -webkit-transform: translateY(0); - transform: translateY(0); - } -} - -.socialIcons { - display: flex; - gap: 16px; - justify-content: center; -} diff --git a/src/screens/UserPortal/UserLoginPage/UserLoginPage.tsx b/src/screens/UserPortal/UserLoginPage/UserLoginPage.tsx deleted file mode 100644 index 23aa7f21d7..0000000000 --- a/src/screens/UserPortal/UserLoginPage/UserLoginPage.tsx +++ /dev/null @@ -1,628 +0,0 @@ -import { useMutation } from '@apollo/client'; -import type { ChangeEvent } from 'react'; -import React, { useEffect, useRef, useState } from 'react'; -import { Form } from 'react-bootstrap'; -import Button from 'react-bootstrap/Button'; -import Col from 'react-bootstrap/Col'; -import Row from 'react-bootstrap/Row'; -import ReCAPTCHA from 'react-google-recaptcha'; -import { useTranslation } from 'react-i18next'; -import { Link, useHistory } from 'react-router-dom'; -import { toast } from 'react-toastify'; - -import { - FacebookLogo, - LinkedInLogo, - GithubLogo, - InstagramLogo, - SlackLogo, - TwitterLogo, - YoutubeLogo, -} from 'assets/svgs/social-icons'; - -import { - REACT_APP_USE_RECAPTCHA, - RECAPTCHA_SITE_KEY, - BACKEND_URL, -} from 'Constant/constant'; -import { - LOGIN_MUTATION, - RECAPTCHA_MUTATION, - SIGNUP_MUTATION, -} from 'GraphQl/Mutations/mutations'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; -import { ReactComponent as PalisadoesLogo } from 'assets/svgs/palisadoes.svg'; -import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; -import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; -import Loader from 'components/Loader/Loader'; -import { errorHandler } from 'utils/errorHandler'; -import styles from './UserLoginPage.module.css'; -import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; - -function loginPage(): JSX.Element { - const { t } = useTranslation('translation', { keyPrefix: 'userLoginPage' }); - const history = useHistory(); - - document.title = t('title'); - - const [showTab, setShowTab] = useState<'LOGIN' | 'REGISTER'>('LOGIN'); - const [componentLoader, setComponentLoader] = useState(true); - const [isInputFocused, setIsInputFocused] = useState(false); - const [signformState, setSignFormState] = useState({ - signfirstName: '', - signlastName: '', - signEmail: '', - signPassword: '', - cPassword: '', - }); - const [formState, setFormState] = useState({ - email: '', - password: '', - }); - const [showPassword, setShowPassword] = useState(false); - const [showConfirmPassword, setShowConfirmPassword] = - useState(false); - const recaptchaRef = useRef(null); - - useEffect(() => { - const isLoggedIn = localStorage.getItem('IsLoggedIn'); - if (isLoggedIn == 'TRUE') { - history.push('/user/organizations/'); - } - setComponentLoader(false); - }, []); - - const togglePassword = (): void => setShowPassword(!showPassword); - const toggleConfirmPassword = (): void => - setShowConfirmPassword(!showConfirmPassword); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [login, { loading: loginLoading }] = useMutation(LOGIN_MUTATION); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [signup, { loading: signinLoading }] = useMutation(SIGNUP_MUTATION); - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const [recaptcha, { loading: recaptchaLoading }] = - useMutation(RECAPTCHA_MUTATION); - - useEffect(() => { - async function loadResource(): Promise { - try { - await fetch(BACKEND_URL as string); - } catch (error: any) { - /* istanbul ignore next */ - errorHandler(t, error); - } - } - - loadResource(); - }, []); - - const verifyRecaptcha = async ( - recaptchaToken: any - ): Promise => { - try { - /* istanbul ignore next */ - if (REACT_APP_USE_RECAPTCHA !== 'yes') { - return true; - } - const { data } = await recaptcha({ - variables: { - recaptchaToken, - }, - }); - - return data.recaptcha; - } catch (error: any) { - /* istanbul ignore next */ - toast.error(t('captchaError')); - } - }; - - const signupLink = async (e: ChangeEvent): Promise => { - e.preventDefault(); - - const { signfirstName, signlastName, signEmail, signPassword, cPassword } = - signformState; - - const recaptchaToken = recaptchaRef.current?.getValue(); - recaptchaRef.current?.reset(); - - const isVerified = await verifyRecaptcha(recaptchaToken); - /* istanbul ignore next */ - if (!isVerified) { - toast.error(t('Please_check_the_captcha')); - return; - } - - if ( - signfirstName.length > 1 && - signlastName.length > 1 && - signEmail.length >= 8 && - signPassword.length > 1 - ) { - if (cPassword == signPassword) { - try { - const { data: signUpData } = await signup({ - variables: { - firstName: signfirstName, - lastName: signlastName, - email: signEmail, - password: signPassword, - }, - }); - - /* istanbul ignore next */ - if (signUpData) { - toast.success(t('afterRegister')); - - setShowTab('LOGIN'); - - setSignFormState({ - signfirstName: '', - signlastName: '', - signEmail: '', - signPassword: '', - cPassword: '', - }); - } - } catch (error: any) { - /* istanbul ignore next */ - errorHandler(t, error); - } - } else { - toast.warn(t('passwordMismatches')); - } - } else { - toast.warn(t('fillCorrectly')); - } - }; - - const loginLink = async (e: ChangeEvent): Promise => { - e.preventDefault(); - - const recaptchaToken = recaptchaRef.current?.getValue(); - recaptchaRef.current?.reset(); - - const isVerified = await verifyRecaptcha(recaptchaToken); - /* istanbul ignore next */ - if (!isVerified) { - toast.error(t('Please_check_the_captcha')); - return; - } - - try { - const { data: loginData } = await login({ - variables: { - email: formState.email, - password: formState.password, - }, - }); - - /* istanbul ignore next */ - if (loginData) { - localStorage.setItem('token', loginData.login.accessToken); - localStorage.setItem('userId', loginData.login.user._id); - localStorage.setItem('refreshToken', loginData.login.refreshToken); - localStorage.setItem('IsLoggedIn', 'TRUE'); - navigator.clipboard.writeText(''); - if (localStorage.getItem('IsLoggedIn') == 'TRUE') { - history.push('/user/organizations/'); - } - } else { - toast.warn(t('notAuthorised')); - } - } catch (error: any) { - /* istanbul ignore next */ - errorHandler(t, error); - } - }; - - if (componentLoader || loginLoading || signinLoading || recaptchaLoading) { - return ; - } - - return ( - <> -
- - -
- -

{t('fromPalisadoes')}

-
- - - - -
- - - - - - {/* LOGIN FORM */} -
-
-

- {t('userLogin')} -

- {t('email')} -
- { - setFormState({ - ...formState, - email: e.target.value, - }); - }} - autoComplete="username" - data-testid="loginEmail" - /> - -
- {t('password')} -
- { - setFormState({ - ...formState, - password: e.target.value, - }); - }} - autoComplete="current-password" - /> - -
-
- - {t('forgotPassword')} - -
- {REACT_APP_USE_RECAPTCHA === 'yes' ? ( -
- -
- ) : ( - /* istanbul ignore next */ - <> - )} - -
-
- {t('OR')} -
- -
-
- {/* REGISTER FORM */} -
-
-

- {t('register')} -

- - -
- {t('firstName')} - { - setSignFormState({ - ...signformState, - signfirstName: e.target.value, - }); - }} - /> -
- - -
- {t('lastName')} - { - setSignFormState({ - ...signformState, - signlastName: e.target.value, - }); - }} - /> -
- -
-
- {t('email')} -
- { - setSignFormState({ - ...signformState, - signEmail: e.target.value.toLowerCase(), - }); - }} - /> - -
-
- -
- {t('password')} -
- setIsInputFocused(true)} - onBlur={(): void => setIsInputFocused(false)} - required - value={signformState.signPassword} - onChange={(e): void => { - setSignFormState({ - ...signformState, - signPassword: e.target.value, - }); - }} - /> - -
- {isInputFocused && - signformState.signPassword.length < 8 && ( -
- {t('atleast_8_char_long')} -
- )} - {!isInputFocused && - signformState.signPassword.length > 0 && - signformState.signPassword.length < 8 && ( -
- {t('atleast_8_char_long')} -
- )} -
-
- {t('confirmPassword')} -
- { - setSignFormState({ - ...signformState, - cPassword: e.target.value, - }); - }} - data-testid="cpassword" - autoComplete="new-password" - /> - -
- {signformState.cPassword.length > 0 && - signformState.signPassword !== - signformState.cPassword && ( -
- {t('Password_and_Confirm_password_mismatches.')} -
- )} -
- {REACT_APP_USE_RECAPTCHA === 'yes' ? ( -
- -
- ) : ( - /* istanbul ignore next */ - <> - )} - -
-
- {t('OR')} -
- -
-
-
- -
-
- - ); -} - -export default loginPage;