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');
+ });
+});