Added change password form on login page

This commit is contained in:
bourquecharles
2021-07-17 13:10:41 -04:00
parent 7830023db3
commit 235f9d6a98
4 changed files with 198 additions and 51 deletions

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "ucentral-libs", "name": "ucentral-libs",
"version": "0.8.13", "version": "0.8.14",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "ucentral-libs", "name": "ucentral-libs",
"version": "0.8.13", "version": "0.8.14",
"devDependencies": { "devDependencies": {
"@babel/core": "^7.14.6", "@babel/core": "^7.14.6",
"@babel/plugin-proposal-class-properties": "^7.14.5", "@babel/plugin-proposal-class-properties": "^7.14.5",

View File

@@ -1,6 +1,6 @@
{ {
"name": "ucentral-libs", "name": "ucentral-libs",
"version": "0.8.13", "version": "0.8.14",
"main": "dist/index.js", "main": "dist/index.js",
"source": "src/index.js", "source": "src/index.js",
"engines": { "engines": {

View File

@@ -0,0 +1,118 @@
import React from 'react';
import {
CButton,
CCol,
CForm,
CInput,
CInputGroup,
CInputGroupPrepend,
CInputGroupText,
CRow,
CSpinner,
CPopover,
CAlert,
CInvalidFeedback,
} from '@coreui/react';
import PropTypes from 'prop-types';
import CIcon from '@coreui/icons-react';
import { cilLockLocked } from '@coreui/icons';
import LanguageSwitcher from '../LanguageSwitcher';
import styles from './index.module.scss';
const ChangePasswordForm = ({
t,
i18n,
onKeyDown,
signIn,
loading,
fields,
updateField,
changePasswordResponse,
cancelPasswordChange,
}) => (
<CForm onKeyDown={(e) => onKeyDown(e, signIn)}>
<h1>
{t('login.change_password')}
<div className={styles.languageSwitcher}>
<LanguageSwitcher i18n={i18n} />
</div>
</h1>
<p className="text-muted">{t('login.change_password_instructions')}</p>
<CInputGroup className="mb-4">
<CPopover content={t('login.password')}>
<CInputGroupPrepend>
<CInputGroupText>
<CIcon name="cilLockLocked" content={cilLockLocked} />
</CInputGroupText>
</CInputGroupPrepend>
</CPopover>
<CInput
id="newpassword"
invalid={fields.newpassword.error}
autoFocus
required
type="password"
placeholder={t(fields.newpassword.placeholder)}
autoComplete="username"
onChange={updateField}
/>
<CInvalidFeedback className="help-block">{t('login.please_enter_username')}</CInvalidFeedback>
</CInputGroup>
<CInputGroup className="mb-4">
<CPopover content={t('login.password')}>
<CInputGroupPrepend>
<CInputGroupText>
<CIcon content={cilLockLocked} />
</CInputGroupText>
</CInputGroupPrepend>
</CPopover>
<CInput
id="confirmpassword"
invalid={fields.confirmpassword.error}
required
type="password"
placeholder={t(fields.confirmpassword.placeholder)}
autoComplete="current-password"
onChange={updateField}
/>
<CInvalidFeedback className="help-block">{t('login.different_passwords')}</CInvalidFeedback>
</CInputGroup>
<CRow>
<CCol>
<CAlert
show={changePasswordResponse.tried}
color={!changePasswordResponse.error ? 'success' : 'danger'}
>
{changePasswordResponse.text}
</CAlert>
</CCol>
</CRow>
<CRow>
<CCol xs="6">
<CButton color="primary" className="px-4" onClick={() => signIn(true)} disabled={loading}>
{loading ? t('login.changing_password') : t('login.change_password')}
<CSpinner hidden={!loading} color="light" component="span" size="sm" />
</CButton>
</CCol>
<CCol xs="6" className={styles.forgotPassword}>
<CButton variant="ghost" color="primary" onClick={cancelPasswordChange}>
{t('common.cancel')}
</CButton>
</CCol>
</CRow>
</CForm>
);
ChangePasswordForm.propTypes = {
t: PropTypes.func.isRequired,
i18n: PropTypes.instanceOf(Object).isRequired,
onKeyDown: PropTypes.func.isRequired,
signIn: PropTypes.func.isRequired,
loading: PropTypes.bool.isRequired,
fields: PropTypes.instanceOf(Object).isRequired,
updateField: PropTypes.func.isRequired,
changePasswordResponse: PropTypes.instanceOf(Object).isRequired,
cancelPasswordChange: PropTypes.func.isRequired,
};
export default ChangePasswordForm;

View File

@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import styles from './index.module.scss'; import styles from './index.module.scss';
import LoginForm from './LoginForm'; import LoginForm from './LoginForm';
import ForgotPasswordForm from './ForgotPasswordForm'; import ForgotPasswordForm from './ForgotPasswordForm';
import ChangePasswordForm from './ChangePasswordForm';
const LoginPage = ({ const LoginPage = ({
t, t,
@@ -15,56 +16,81 @@ const LoginPage = ({
fields, fields,
updateField, updateField,
isLogin, isLogin,
isPasswordChange,
toggleForgotPassword, toggleForgotPassword,
onKeyDown, onKeyDown,
sendForgotPasswordEmail, sendForgotPasswordEmail,
}) => ( changePasswordResponse,
<div className="c-app c-default-layout flex-row align-items-center"> cancelPasswordChange,
<CContainer> }) => {
<CRow className="justify-content-center"> const getForm = () => {
<CCol md="8"> if (!isLogin) {
<img return (
className={[styles.logo, 'c-sidebar-brand-full'].join(' ')} <ForgotPasswordForm
src="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg" t={t}
alt="OpenWifi" i18n={i18n}
/> onKeyDown={onKeyDown}
<CCardGroup> signIn={signIn}
<CCard className="p-4"> loading={loading}
<CCardBody> fields={fields}
{isLogin ? ( updateField={updateField}
<LoginForm forgotResponse={forgotResponse}
t={t} toggleForgotPassword={toggleForgotPassword}
i18n={i18n} sendForgotPasswordEmail={sendForgotPasswordEmail}
onKeyDown={onKeyDown} />
signIn={signIn} );
loading={loading} }
fields={fields} if (isPasswordChange) {
updateField={updateField} return (
loginResponse={loginResponse} <ChangePasswordForm
toggleForgotPassword={toggleForgotPassword} t={t}
/> i18n={i18n}
) : ( onKeyDown={onKeyDown}
<ForgotPasswordForm signIn={signIn}
t={t} loading={loading}
i18n={i18n} fields={fields}
onKeyDown={onKeyDown} updateField={updateField}
signIn={signIn} changePasswordResponse={changePasswordResponse}
loading={loading} cancelPasswordChange={cancelPasswordChange}
fields={fields} />
updateField={updateField} );
forgotResponse={forgotResponse} }
toggleForgotPassword={toggleForgotPassword} return (
sendForgotPasswordEmail={sendForgotPasswordEmail} <LoginForm
/> t={t}
)} i18n={i18n}
</CCardBody> onKeyDown={onKeyDown}
</CCard> signIn={signIn}
</CCardGroup> loading={loading}
</CCol> fields={fields}
</CRow> updateField={updateField}
</CContainer> loginResponse={loginResponse}
</div> toggleForgotPassword={toggleForgotPassword}
); />
);
};
return (
<div className="c-app c-default-layout flex-row align-items-center">
<CContainer>
<CRow className="justify-content-center">
<CCol md="8">
<img
className={[styles.logo, 'c-sidebar-brand-full'].join(' ')}
src="assets/OpenWiFi_LogoLockup_DarkGreyColour.svg"
alt="OpenWifi"
/>
<CCardGroup>
<CCard className="p-4">
<CCardBody>{getForm()}</CCardBody>
</CCard>
</CCardGroup>
</CCol>
</CRow>
</CContainer>
</div>
);
};
LoginPage.propTypes = { LoginPage.propTypes = {
t: PropTypes.func.isRequired, t: PropTypes.func.isRequired,
@@ -75,10 +101,13 @@ LoginPage.propTypes = {
forgotResponse: PropTypes.instanceOf(Object).isRequired, forgotResponse: PropTypes.instanceOf(Object).isRequired,
fields: PropTypes.instanceOf(Object).isRequired, fields: PropTypes.instanceOf(Object).isRequired,
updateField: PropTypes.func.isRequired, updateField: PropTypes.func.isRequired,
isLogin: PropTypes.func.isRequired, isLogin: PropTypes.bool.isRequired,
isPasswordChange: PropTypes.bool.isRequired,
toggleForgotPassword: PropTypes.func.isRequired, toggleForgotPassword: PropTypes.func.isRequired,
onKeyDown: PropTypes.func.isRequired, onKeyDown: PropTypes.func.isRequired,
sendForgotPasswordEmail: PropTypes.func.isRequired, sendForgotPasswordEmail: PropTypes.func.isRequired,
changePasswordResponse: PropTypes.instanceOf(Object).isRequired,
cancelPasswordChange: PropTypes.func.isRequired,
}; };
export default React.memo(LoginPage); export default React.memo(LoginPage);