Files
frontend-app-authn/src/common-components/PasswordField.jsx
Shafqat Farhan b4387fc576 VAN-484 - Adjusted the PasswordField tooltip position and opacity (#293)
* VAN-484 - Adjusted the PasswordField tooltip position and opacity

* VAN-484 - Adjusted the tooltip width for mobile view
2021-07-27 16:57:14 +05:00

93 lines
3.6 KiB
JavaScript

import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import {
Form, IconButton, useToggle, Tooltip, OverlayTrigger, Icon,
} from '@edx/paragon';
import { Check, Remove } from '@edx/paragon/icons';
import { faEye, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
import messages from './messages';
import { LETTER_REGEX, NUMBER_REGEX } from '../data/constants';
const PasswordField = (props) => {
const { formatMessage } = props.intl;
const [isPasswordHidden, setHiddenTrue, setHiddenFalse] = useToggle(true);
const [showTooltip, setShowTooltip] = useState(false);
const handleBlur = (e) => {
if (props.handleBlur) { props.handleBlur(e); }
setShowTooltip(props.showRequirements && false);
};
const HideButton = (
<IconButton icon={faEyeSlash} onClick={setHiddenTrue} alt={formatMessage(messages['hide.password'])} aria-label={formatMessage(messages['hide.password'])} />
);
const ShowButton = (
<IconButton icon={faEye} onClick={setHiddenFalse} alt={formatMessage(messages['show.password'])} aria-label={formatMessage(messages['show.password'])} />
);
const placement = window.innerWidth < 768 ? 'top' : 'left';
const tooltip = (
<Tooltip id={`password-requirement-${placement}`}>
<span id="letter-check" className="d-flex position-relative align-content-start">
{LETTER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
{formatMessage(messages['one.letter'])}
</span>
<span id="number-check" className="d-flex position-relative align-content-start">
{NUMBER_REGEX.test(props.value) ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
{formatMessage(messages['one.number'])}
</span>
<span id="characters-check" className="d-flex position-relative align-content-start">
{props.value.length >= 8 ? <Icon className="text-success mr-1" src={Check} /> : <Icon className="mr-1" src={Remove} />}
{formatMessage(messages['eight.characters'])}
</span>
</Tooltip>
);
return (
<Form.Group controlId={props.name} className="mb-4" isInvalid={props.errorMessage !== ''}>
<OverlayTrigger key="tooltip" placement={placement} overlay={tooltip} show={showTooltip}>
<Form.Control
as="input"
type={isPasswordHidden ? 'password' : 'text'}
name={props.name}
value={props.value}
onFocus={() => setTimeout(() => setShowTooltip(props.showRequirements && true), 150)}
onBlur={handleBlur}
onChange={props.handleChange}
controlClassName={props.borderClass}
trailingElement={isPasswordHidden ? ShowButton : HideButton}
floatingLabel={props.floatingLabel}
/>
</OverlayTrigger>
{props.errorMessage !== '' && (
<Form.Control.Feedback key="error" feedback-for={props.name} type="invalid">{props.errorMessage}</Form.Control.Feedback>
)}
</Form.Group>
);
};
PasswordField.defaultProps = {
borderClass: '',
errorMessage: '',
handleBlur: null,
handleChange: () => {},
showRequirements: true,
};
PasswordField.propTypes = {
borderClass: PropTypes.string,
errorMessage: PropTypes.string,
floatingLabel: PropTypes.string.isRequired,
handleBlur: PropTypes.func,
handleChange: PropTypes.func,
intl: intlShape.isRequired,
name: PropTypes.string.isRequired,
showRequirements: PropTypes.bool,
value: PropTypes.string.isRequired,
};
export default injectIntl(PasswordField);