Files
freeCodeCamp/client/src/client-only-routes/show-update-email.tsx
T
2025-07-28 18:25:14 +05:30

139 lines
3.7 KiB
TypeScript

import React, {
useState,
useEffect,
type FormEvent,
type ChangeEvent
} from 'react';
import Helmet from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import isEmail from 'validator/lib/isEmail';
import {
Container,
FormGroup,
FormControl,
ControlLabel,
Col,
Row,
Button,
Spacer
} from '@freecodecamp/ui';
import envData from '../../config/env.json';
import { Loader, Link } from '../components/helpers';
import './show-update-email.css';
import { isSignedInSelector, userSelector } from '../redux/selectors';
import { hardGoTo as navigate } from '../redux/actions';
import { updateMyEmail } from '../redux/settings/actions';
import { maybeEmailRE } from '../utils';
import type { User } from '../redux/prop-types';
const { apiLocation } = envData;
interface ShowUpdateEmailProps {
isNewEmail: boolean;
updateMyEmail: (e: string) => void;
path?: string;
isSignedIn: boolean;
navigate: (location: string) => void;
}
const mapStateToProps = createSelector(
userSelector,
isSignedInSelector,
(user: User | null, isSignedIn) => ({
isNewEmail: !user?.email || user.emailVerified,
isSignedIn
})
);
const mapDispatchToProps = { updateMyEmail, navigate };
function ShowUpdateEmail({
isNewEmail,
updateMyEmail,
isSignedIn,
navigate
}: ShowUpdateEmailProps) {
const { t } = useTranslation();
const [emailValue, setEmailValue] = useState('');
useEffect(() => {
if (!isSignedIn) navigate(`${apiLocation}/signin`);
}, [isSignedIn, navigate]);
if (!isSignedIn) return <Loader fullScreen={true} />;
function handleSubmit(event: FormEvent) {
event.preventDefault();
updateMyEmail(emailValue);
}
function onChange(event: ChangeEvent<HTMLInputElement>) {
setEmailValue(event.target.value);
return null;
}
const emailValidationState = maybeEmailRE.test(emailValue)
? isEmail(emailValue)
? 'success'
: 'error'
: null;
return (
<>
<Helmet>
<title>{t('misc.update-email-1')} | freeCodeCamp.org</title>
</Helmet>
<Container>
<Spacer size='m' />
<h2 className='text-center'>{t('misc.update-email-2')}</h2>
<Row>
<Col sm={6} smOffset={3}>
<Row>
<form
onSubmit={handleSubmit}
data-playwright-test-label='update-email-form'
>
<FormGroup
className='update-email-field'
validationState={emailValidationState}
>
<ControlLabel htmlFor='emailInput'>
{t('misc.email')}
</ControlLabel>
<FormControl
id='emailInput'
onChange={onChange}
placeholder='camperbot@example.com'
required={true}
type='email'
/>
</FormGroup>
<Button
block={true}
size='large'
variant='primary'
disabled={emailValidationState !== 'success'}
type='submit'
>
{isNewEmail
? t('buttons.update-email')
: t('buttons.verify-email')}
</Button>
</form>
<p className='text-center'>
<Link to='/signout'>{t('buttons.sign-out')}</Link>
</p>
</Row>
</Col>
</Row>
</Container>
</>
);
}
ShowUpdateEmail.displayName = 'ShowUpdateEmail';
export default connect(mapStateToProps, mapDispatchToProps)(ShowUpdateEmail);