import { createStyles, makeStyles, TextField } from "@material-ui/core"; import FormHelperText from "@material-ui/core/FormHelperText"; import IconButton from "@material-ui/core/IconButton"; import InputAdornment from "@material-ui/core/InputAdornment"; import React, { useState } from "react"; import { Eye, EyeOff } from "react-feather"; import { Theme } from "../theme"; const useStyles = makeStyles((theme: Theme) => createStyles({ iconButton: { padding: theme.spacing(0.5), }, }) ); type Props = { onChangePassword: (password: string) => void; onChangeValid: (valid: boolean) => void; onChangeShowPassword: VoidFunction; showPassword: boolean; className?: string; }; const errorMessages = { length: "between 6 and 26 characters", lowerCase: "one lowercase letter", upperCase: "one uppercase letter", number: "a number", specialChar: "a special character", noSpaces: "no spaces", }; const PasswordTextField = ({ onChangePassword, onChangeValid, onChangeShowPassword, showPassword, className, }: Props) => { const classes = useStyles(); const [errors, setErrors] = useState<string[]>([]); const handleChange = () => { if (errors.length > 0) { setErrors([]); onChangeValid(true); } }; const handleBlur = (event: React.FocusEvent<HTMLInputElement>) => { const password = event.target.value; if (password) { onChangePassword(password); const errors = []; // length if (password.match(/^(?=.{6,26})/g) === null) errors.push(errorMessages.length); // lower case if (password.match(/^(?=.*[a-z])/g) === null) errors.push(errorMessages.lowerCase); // upper case if (password.match(/^(?=.*[A-Z])/g) === null) errors.push(errorMessages.upperCase); // number if (password.match(/^(?=.*[0-9])/g) === null) errors.push(errorMessages.number); // special char // if (password.match(/^(?=.*[!@#$%^&*])/g) === null) errors.push(errorMessages.specialChar); // spaces if (password.match(/\s/g) !== null) errors.push(errorMessages.noSpaces); onChangeValid(errors.length === 0); setErrors(errors); } }; return ( <TextField id="email" color="secondary" name="password" autoComplete="password" onChange={handleChange} onBlur={handleBlur} label="Password" variant="outlined" type={showPassword ? "text" : "password"} size="small" required className={className} InputProps={{ endAdornment: ( <InputAdornment position="end"> <IconButton aria-label="Toggle password visibility" onClick={onChangeShowPassword} className={classes.iconButton} > {showPassword ? <EyeOff size={20} /> : <Eye size={20} />} </IconButton> </InputAdornment> ), }} error={Boolean(errors.length)} helperText={ errors.length > 0 && ( <> <FormHelperText id="name-error-text"> Password must contain: </FormHelperText> {errors.map((error) => ( <FormHelperText id="name-error-text">- {error}</FormHelperText> ))} </> ) } /> ); }; export default PasswordTextField;