import React, { Component, Fragment } from 'react'; import PropTypes from 'prop-types'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { createSelector } from 'reselect'; import { ControlLabel, FormControl, Alert, FormGroup } from '@freecodecamp/react-bootstrap'; import isAscii from 'validator/lib/isAscii'; import { validateUsername, usernameValidationSelector, submitNewUsername } from '../../redux/settings'; import BlockSaveButton from '../helpers/form/BlockSaveButton'; import FullWidthRow from '../helpers/FullWidthRow'; const propTypes = { isValidUsername: PropTypes.bool, submitNewUsername: PropTypes.func.isRequired, username: PropTypes.string, validateUsername: PropTypes.func.isRequired, validating: PropTypes.bool }; const mapStateToProps = createSelector( usernameValidationSelector, ({ isValidUsername, fetchState }) => ({ isValidUsername, validating: fetchState.pending }) ); const mapDispatchToProps = dispatch => bindActionCreators( { submitNewUsername, validateUsername }, dispatch ); const invalidCharsRE = /[/\s?:@=&"'<>#%{}|\\^~[\]`,.;!*()$]/; const invlaidCharError = { valid: false, error: 'Username contains invalid characters' }; const valididationSuccess = { valid: true, error: null }; const usernameTooShort = { valid: false, error: 'Username is too short' }; class UsernameSettings extends Component { constructor(props) { super(props); this.state = { isFormPristine: true, formValue: props.username, characterValidation: { valid: false, error: null }, sumbitClicked: false }; this.handleChange = this.handleChange.bind(this); this.handleSubmit = this.handleSubmit.bind(this); this.validateFormInput = this.validateFormInput.bind(this); } componentDidUpdate(prevProps, prevState) { const { username: prevUsername } = prevProps; const { formValue: prevFormValue } = prevState; const { username } = this.props; const { formValue } = this.state; if (prevUsername !== username && prevFormValue === formValue) { /* eslint-disable-next-line react/no-did-update-set-state */ return this.setState({ isFormPristine: username === formValue, sumbitClicked: false }); } return null; } handleSubmit(e) { e.preventDefault(); const { submitNewUsername } = this.props; const { formValue, characterValidation: { valid } } = this.state; return this.setState( { sumbitClicked: true }, () => (valid ? submitNewUsername(formValue) : null) ); } handleChange(e) { e.preventDefault(); const { username, validateUsername } = this.props; const newValue = e.target.value.toLowerCase(); return this.setState( { formValue: newValue, isFormPristine: username === newValue, characterValidation: this.validateFormInput(newValue) }, () => this.state.isFormPristine || this.state.characterValidation.error ? null : validateUsername(this.state.formValue) ); } validateFormInput(formValue) { if (formValue.length < 3) { return usernameTooShort; } if (!isAscii(formValue)) { return invlaidCharError; } if (invalidCharsRE.test(formValue)) { return invlaidCharError; } return valididationSuccess; } renderAlerts(validating, error, isValidUsername) { if (!validating && error) { return ( {error} ); } if (!validating && !isValidUsername) { console.log(this.props, this.state); return ( Username not available ); } if (validating) { return ( Validating username ); } if (!validating && isValidUsername) { return ( Username is available ); } return null; } render() { const { isFormPristine, formValue, characterValidation: { valid, error }, sumbitClicked } = this.state; const { isValidUsername, validating } = this.props; return (
Username {!isFormPristine && this.renderAlerts(validating, error, isValidUsername)}
); } } UsernameSettings.displayName = 'UsernameSettings'; UsernameSettings.propTypes = propTypes; export default connect( mapStateToProps, mapDispatchToProps )(UsernameSettings);