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
|
|
|
|
);
|
|
|
|
|
2019-11-04 18:54:18 +05:30
|
|
|
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 },
|
2019-11-04 18:54:18 +05:30
|
|
|
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,
|
2019-11-04 18:54:18 +05:30
|
|
|
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;
|
|
|
|
|
2019-02-19 01:59:12 +03:00
|
|
|
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,
|
2019-11-11 20:21:00 +01:00
|
|
|
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>
|
2019-11-04 18:54:18 +05:30
|
|
|
<Alert bsStyle='warning'>Username not available.</Alert>
|
2018-09-13 18:28:23 +01:00
|
|
|
</FullWidthRow>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if (validating) {
|
|
|
|
return (
|
|
|
|
<FullWidthRow>
|
2019-11-04 18:54:18 +05:30
|
|
|
<Alert bsStyle='info'>Validating username...</Alert>
|
2018-09-13 18:28:23 +01:00
|
|
|
</FullWidthRow>
|
|
|
|
);
|
|
|
|
}
|
2019-11-04 18:54:18 +05:30
|
|
|
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>
|
2019-11-04 18:54:18 +05:30
|
|
|
<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);
|