import React, { Component } from 'react'; import zxcvbn, { ZXCVBNResult } from 'zxcvbn'; import translate, { translateRaw } from 'translations'; import { MINIMUM_PASSWORD_LENGTH } from 'config'; import { Spinner } from 'components/ui'; import Template from '../Template'; import './EnterPassword.scss'; import { TogglablePassword } from 'components'; interface Props { isGenerating: boolean; continue(pw: string): void; } interface State { password: string; confirmedPassword: string; passwordValidation: ZXCVBNResult | null; feedback: string; } export default class EnterPassword extends Component { public state: State = { password: '', confirmedPassword: '', passwordValidation: null, feedback: '' }; public render() { const { isGenerating } = this.props; const { password, confirmedPassword, feedback } = this.state; const passwordValidity = this.getPasswordValidity(); const isPasswordValid = passwordValidity === 'valid'; const isConfirmValid = confirmedPassword ? password === confirmedPassword : undefined; const canSubmit = isPasswordValid && isConfirmValid && !isGenerating; return ( ); } private getPasswordValidity(): 'valid' | 'invalid' | 'semivalid' | undefined { const { password, passwordValidation } = this.state; if (!password) { return undefined; } if (password.length < MINIMUM_PASSWORD_LENGTH) { return 'invalid'; } if (passwordValidation && passwordValidation.score < 3) { return 'semivalid'; } return 'valid'; } private getFeedback() { let feedback: string = ''; const validity = this.getPasswordValidity(); if (validity !== 'valid') { const { password, passwordValidation } = this.state; if (password.length < MINIMUM_PASSWORD_LENGTH) { feedback = translateRaw('INPUT_PASSWORD_PLACEHOLDER', { $pass_length: MINIMUM_PASSWORD_LENGTH.toString() }); } else if (passwordValidation && passwordValidation.feedback) { feedback = translateRaw('WEAK_PASSWORD') + ' ' + passwordValidation.feedback.warning; } else { feedback = translateRaw('INVALID_PASSWORD'); } } return feedback; } private handleSubmit = (ev: React.FormEvent) => { ev.preventDefault(); this.props.continue(this.state.password); }; private onPasswordChange = (e: React.FormEvent) => { const password = e.currentTarget.value; const passwordValidation = password ? zxcvbn(password) : null; this.setState( { password, passwordValidation, feedback: '' }, () => { if (password.length >= MINIMUM_PASSWORD_LENGTH) { this.showFeedback(); } } ); }; private onConfirmChange = (e: React.FormEvent) => { this.setState({ confirmedPassword: e.currentTarget.value }); }; private showFeedback = () => { const { password, passwordValidation } = this.state; if (!password) { return; } const feedback = this.getFeedback(); this.setState({ passwordValidation, feedback }); }; }