Files
frontend-app-authn/src/register/RegistrationFields/EmailField/EmailField.jsx

143 lines
4.1 KiB
JavaScript

import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
import { Alert, Icon } from '@edx/paragon';
import { Close, Error } from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import validateEmail from './validator';
import { FormGroup } from '../../../common-components';
import {
clearRegistrationBackendError,
fetchRealtimeValidations,
setEmailSuggestionInStore,
} from '../../data/actions';
import messages from '../../messages';
/**
* Email field wrapper. It accepts following handlers
* - handleChange for setting value change and
* - handleErrorChange for setting error
*
* It is responsible for
* - Generating email warning and error suggestions
* - Setting and clearing email suggestions
* - Performing email field validations
* - clearing error on focus
* - setting value on change
*/
const EmailField = (props) => {
const { formatMessage } = useIntl();
const dispatch = useDispatch();
const {
handleChange,
handleErrorChange,
confirmEmailValue,
} = props;
const {
registrationFormData: backedUpFormData,
validationApiRateLimited,
} = useSelector(state => state.register);
const [emailSuggestion, setEmailSuggestion] = useState({ ...backedUpFormData?.emailSuggestion });
useEffect(() => {
setEmailSuggestion(backedUpFormData.emailSuggestion);
}, [backedUpFormData.emailSuggestion]);
const handleOnBlur = (e) => {
const { value } = e.target;
const { fieldError, confirmEmailError, suggestion } = validateEmail(value, confirmEmailValue, formatMessage);
if (confirmEmailError) {
handleErrorChange('confirm_email', confirmEmailError);
}
dispatch(setEmailSuggestionInStore(suggestion));
setEmailSuggestion(suggestion);
if (fieldError) {
handleErrorChange('email', fieldError);
} else if (!validationApiRateLimited) {
dispatch(fetchRealtimeValidations({ email: value }));
}
};
const handleOnFocus = () => {
handleErrorChange('email', '');
dispatch(clearRegistrationBackendError('email'));
};
const handleSuggestionClick = (event) => {
event.preventDefault();
handleErrorChange('email', '');
handleChange({ target: { name: 'email', value: emailSuggestion.suggestion } });
setEmailSuggestion({ suggestion: '', type: '' });
};
const handleSuggestionClosed = () => setEmailSuggestion({ suggestion: '', type: '' });
const renderEmailFeedback = () => {
if (emailSuggestion.type === 'error') {
return (
<Alert variant="danger" className="email-suggestion-alert-error mt-1" icon={Error}>
<span className="email-suggestion__text">
{formatMessage(messages['did.you.mean.alert.text'])}{' '}
<Alert.Link
href="#"
name="email"
onClick={handleSuggestionClick}
>
{emailSuggestion.suggestion}
</Alert.Link>?
<Icon src={Close} className="email-suggestion__close" onClick={handleSuggestionClosed} tabIndex="0" />
</span>
</Alert>
);
}
return (
<span id="email-warning" className="small">
{formatMessage(messages['did.you.mean.alert.text'])}:{' '}
<Alert.Link
href="#"
name="email"
className="email-suggestion-alert-warning"
onClick={handleSuggestionClick}
>
{emailSuggestion.suggestion}
</Alert.Link>?
</span>
);
};
return (
<FormGroup
borderClass={emailSuggestion.type === 'warning' ? 'yellow-border' : ''}
maxLength={254} // Limit per RFCs is 254
{...props}
handleBlur={handleOnBlur}
handleFocus={handleOnFocus}
>
{emailSuggestion.suggestion ? renderEmailFeedback() : null}
</FormGroup>
);
};
EmailField.defaultProps = {
errorMessage: '',
confirmEmailValue: null,
};
EmailField.propTypes = {
errorMessage: PropTypes.string,
value: PropTypes.string.isRequired,
handleChange: PropTypes.func.isRequired,
handleErrorChange: PropTypes.func.isRequired,
confirmEmailValue: PropTypes.string,
};
export default EmailField;