Files
freeCodeCamp/client/src/components/settings/Username.js

206 lines
5.5 KiB
JavaScript
Raw Normal View History

2018-09-13 18:28:23 +01:00
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 {
validateUsername,
usernameValidationSelector,
submitNewUsername
} from '../../redux/settings';
import BlockSaveButton from '../helpers/form/BlockSaveButton';
import FullWidthRow from '../helpers/FullWidthRow';
2019-11-11 20:05:05 +01:00
import { validate } from '../../../../utils/validate';
2018-09-13 18:28:23 +01:00
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 hex = '[0-9a-f]';
const tempUserRegex = new RegExp(`^fcc${hex}{8}-(${hex}{4}-){3}${hex}{12}$`);
2018-09-13 18:28:23 +01:00
class UsernameSettings extends Component {
constructor(props) {
super(props);
this.state = {
isFormPristine: true,
formValue: props.username,
characterValidation: { valid: false, error: null },
submitClicked: false,
isUserNew: tempUserRegex.test(props.username)
2018-09-13 18:28:23 +01:00
};
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,
submitClicked: false,
isUserNew: tempUserRegex.test(username)
2018-09-13 18:28:23 +01:00
});
}
return null;
}
handleSubmit(e) {
e.preventDefault();
const { submitNewUsername } = this.props;
const {
formValue,
characterValidation: { valid }
} = this.state;
return this.setState({ submitClicked: true }, () =>
valid ? submitNewUsername(formValue) : null
2018-09-13 18:28:23 +01:00
);
}
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),
submitClicked: false
2018-09-13 18:28:23 +01:00
},
() =>
this.state.isFormPristine || this.state.characterValidation.error
? null
: validateUsername(this.state.formValue)
);
}
validateFormInput(formValue) {
2019-11-11 20:05:05 +01:00
return validate(formValue);
2018-09-13 18:28:23 +01:00
}
renderAlerts(validating, error, isValidUsername) {
if (!validating && error) {
return (
<FullWidthRow>
2019-11-11 20:05:05 +01:00
<Alert bsStyle='danger'>{'Username ' + error}</Alert>
2018-09-13 18:28:23 +01:00
</FullWidthRow>
);
}
if (!validating && !isValidUsername) {
return (
<FullWidthRow>
<Alert bsStyle='warning'>Username not available.</Alert>
2018-09-13 18:28:23 +01:00
</FullWidthRow>
);
}
if (validating) {
return (
<FullWidthRow>
<Alert bsStyle='info'>Validating username...</Alert>
2018-09-13 18:28:23 +01:00
</FullWidthRow>
);
}
if (!validating && isValidUsername && this.state.isUserNew) {
return (
<FullWidthRow>
<Alert bsStyle='success'>Username is available.</Alert>
</FullWidthRow>
);
} else if (!validating && isValidUsername && !this.state.isUserNew) {
2018-09-13 18:28:23 +01:00
return (
<FullWidthRow>
<Alert bsStyle='success'>Username is available.</Alert>
<Alert bsStyle='info'>
Please note, changing your username will also change the URL to your
profile and your certifications.
</Alert>
2018-09-13 18:28:23 +01:00
</FullWidthRow>
);
}
return null;
}
render() {
const {
isFormPristine,
formValue,
characterValidation: { valid, error },
2018-11-14 00:16:47 +02:00
submitClicked
2018-09-13 18:28:23 +01:00
} = this.state;
const { isValidUsername, validating } = this.props;
return (
<Fragment>
<form id='usernameSettings' onSubmit={this.handleSubmit}>
<FullWidthRow>
<FormGroup>
<ControlLabel htmlFor='username-settings'>
<strong>Username</strong>
</ControlLabel>
<FormControl
name='username-settings'
onChange={this.handleChange}
value={formValue}
/>
</FormGroup>
</FullWidthRow>
{!isFormPristine &&
this.renderAlerts(validating, error, isValidUsername)}
<FullWidthRow>
<BlockSaveButton
disabled={
2018-11-14 00:16:47 +02:00
!(isValidUsername && valid && !isFormPristine) || submitClicked
2018-09-13 18:28:23 +01:00
}
/>
</FullWidthRow>
</form>
</Fragment>
);
}
}
UsernameSettings.displayName = 'UsernameSettings';
UsernameSettings.propTypes = propTypes;
export default connect(
mapStateToProps,
mapDispatchToProps
)(UsernameSettings);