diff --git a/client/src/components/settings/About.js b/client/src/components/settings/About.js index 166b64545e..3e058ed3b8 100644 --- a/client/src/components/settings/About.js +++ b/client/src/components/settings/About.js @@ -3,7 +3,9 @@ import PropTypes from 'prop-types'; import { FormGroup, ControlLabel, - FormControl + FormControl, + HelpBlock, + Alert } from '@freecodecamp/react-bootstrap'; import { FullWidthRow, Spacer } from '../helpers'; @@ -28,7 +30,7 @@ const propTypes = { class AboutSettings extends Component { constructor(props) { super(props); - + this.validationImage = new Image(); const { name = '', location = '', picture = '', about = '' } = props; const values = { name, @@ -39,7 +41,8 @@ class AboutSettings extends Component { this.state = { formValues: { ...values }, originalValues: { ...values }, - formClicked: false + formClicked: false, + isPictureUrlValid: true }; } @@ -69,18 +72,25 @@ class AboutSettings extends Component { isFormPristine = () => { const { formValues, originalValues } = this.state; - return Object.keys(originalValues) - .map(key => originalValues[key] === formValues[key]) - .every(bool => bool); + return ( + this.state.isPictureUrlValid === false || + Object.keys(originalValues) + .map(key => originalValues[key] === formValues[key]) + .every(bool => bool) + ); }; handleSubmit = e => { e.preventDefault(); const { formValues } = this.state; const { submitNewAbout } = this.props; - return this.setState({ formClicked: true }, () => - submitNewAbout(formValues) - ); + if (this.state.isPictureUrlValid === true) { + return this.setState({ formClicked: true }, () => + submitNewAbout(formValues) + ); + } else { + return false; + } }; handleNameChange = e => { @@ -103,8 +113,22 @@ class AboutSettings extends Component { })); }; + componentDidMount() { + this.validationImage.addEventListener('error', this.errorEvent); + this.validationImage.addEventListener('load', this.loadEvent); + } + + componentWillUnmount() { + this.validationImage.removeEventListener('load', this.loadEvent); + this.validationImage.removeEventListener('error', this.errorEvent); + } + + loadEvent = () => this.setState({ isPictureUrlValid: true }); + errorEvent = () => this.setState({ isPictureUrlValid: false }); + handlePictureChange = e => { const value = e.target.value.slice(0); + this.validationImage.src = value; return this.setState(state => ({ formValues: { ...state.formValues, @@ -113,6 +137,19 @@ class AboutSettings extends Component { })); }; + showImageValidationWarning = () => { + const { t } = this.props; + if (this.state.isPictureUrlValid === false) { + return ( + + {t('validation.url-not-image')} + + ); + } else { + return true; + } + }; + handleAboutChange = e => { const value = e.target.value.slice(0); return this.setState(state => ({ @@ -164,6 +201,7 @@ class AboutSettings extends Component { type='url' value={picture} /> + {this.showImageValidationWarning()} diff --git a/cypress/integration/settings/image-picture-check.js b/cypress/integration/settings/image-picture-check.js new file mode 100644 index 0000000000..5bb38e700e --- /dev/null +++ b/cypress/integration/settings/image-picture-check.js @@ -0,0 +1,39 @@ +/* global cy */ + +describe('Picture input field', () => { + beforeEach(() => { + cy.login(); + cy.visit('/settings'); + // Setting aliases here + cy.get('input#about-picture').as('pictureInput'); + }); + + it('Should be possible to type', () => { + cy.get('@pictureInput') + .clear({ force: true }) + .type('twaha', { force: true }) + .should('have.attr', 'value', 'twaha'); + }); + it('Show an error message if an incorrect url was submitted', () => { + cy.get('@pictureInput') + .clear({ force: true }) + .type('https://s3.amazonaws.com/freecodecamp/camper-image', { + force: true + }) + .then(() => { + cy.contains('URL must link directly to an image file'); + }); + }); + it('Can submit a correct URL', () => { + cy.get('@pictureInput') + .clear({ force: true }) + .type( + 'https://s3.amazonaws.com/freecodecamp/camper-image-placeholder.png', + { + force: true + } + ); + cy.wait(500); + cy.get('#camper-identity > .btn').should('not.be.disabled'); + }); +});