mirror of
https://github.com/freeCodeCamp/freeCodeCamp.git
synced 2026-05-28 18:26:54 +00:00
fix: disable portfolio description if over 288 characters (#49730)
* fix: description if characters is over 288 characters on portfolio * feat: add tests * Update client/src/components/helpers/form/block-save-button.tsx
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import {
|
||||
Button,
|
||||
FormGroup,
|
||||
@@ -120,25 +121,6 @@ class PortfolioSettings extends Component<PortfolioProps, PortfolioState> {
|
||||
return isEqual(original, edited);
|
||||
};
|
||||
|
||||
// TODO: Check if this function is required or not
|
||||
// isFormValid = id => {
|
||||
// const { portfolio } = this.state;
|
||||
// const toValidate = find(portfolio, createFindById(id));
|
||||
// if (!toValidate) {
|
||||
// return false;
|
||||
// }
|
||||
// const { title, url, image, description } = toValidate;
|
||||
|
||||
// const { state: titleState } = this.getTitleValidation(title);
|
||||
// const { state: urlState } = this.getUrlValidation(url);
|
||||
// const { state: imageState } = this.getUrlValidation(image, true);
|
||||
// const { state: descriptionState } =
|
||||
// this.getDescriptionValidation(description);
|
||||
// return [titleState, imageState, urlState, descriptionState]
|
||||
// .filter(Boolean)
|
||||
// .every(state => state === 'success');
|
||||
// };
|
||||
|
||||
getDescriptionValidation(description: string) {
|
||||
const { t } = this.props;
|
||||
const len = description.length;
|
||||
@@ -196,6 +178,56 @@ class PortfolioSettings extends Component<PortfolioProps, PortfolioState> {
|
||||
: { state: 'warning', message: t('validation.use-valid-url') };
|
||||
}
|
||||
|
||||
formCorrect(portfolio: PortfolioItem) {
|
||||
const { id, title, description, url, image } = portfolio;
|
||||
|
||||
const { state: titleState, message: titleMessage } =
|
||||
this.getTitleValidation(title);
|
||||
const { state: urlState, message: urlMessage } = this.getUrlValidation(url);
|
||||
const { state: descriptionState, message: descriptionMessage } =
|
||||
this.getDescriptionValidation(description);
|
||||
const { state: imageState, message: imageMessage } = this.getUrlValidation(
|
||||
image,
|
||||
true
|
||||
);
|
||||
const pristine = this.isFormPristine(id);
|
||||
|
||||
const urlIsValid = !isURL(url, {
|
||||
protocols: ['http', 'https'],
|
||||
require_tld: true,
|
||||
require_protocol: true
|
||||
});
|
||||
|
||||
const isButtonDisabled = [
|
||||
titleState,
|
||||
urlState,
|
||||
descriptionState,
|
||||
imageState,
|
||||
urlIsValid
|
||||
].some(state => state === 'error' || false);
|
||||
|
||||
return {
|
||||
isButtonDisabled,
|
||||
title: {
|
||||
titleState,
|
||||
titleMessage
|
||||
},
|
||||
url: {
|
||||
urlState,
|
||||
urlMessage
|
||||
},
|
||||
image: {
|
||||
imageState,
|
||||
imageMessage
|
||||
},
|
||||
desc: {
|
||||
descriptionState,
|
||||
descriptionMessage
|
||||
},
|
||||
pristine
|
||||
};
|
||||
}
|
||||
|
||||
renderPortfolio = (
|
||||
portfolio: PortfolioItem,
|
||||
index: number,
|
||||
@@ -203,31 +235,18 @@ class PortfolioSettings extends Component<PortfolioProps, PortfolioState> {
|
||||
) => {
|
||||
const { t } = this.props;
|
||||
const { id, title, description, url, image } = portfolio;
|
||||
const pristine = this.isFormPristine(id);
|
||||
const { state: titleState, message: titleMessage } =
|
||||
this.getTitleValidation(title);
|
||||
const { state: urlState, message: urlMessage } = this.getUrlValidation(url);
|
||||
const { state: imageState, message: imageMessage } = this.getUrlValidation(
|
||||
image,
|
||||
true
|
||||
);
|
||||
const { state: descriptionState, message: descriptionMessage } =
|
||||
this.getDescriptionValidation(description);
|
||||
|
||||
const isDisabled =
|
||||
pristine ||
|
||||
!title ||
|
||||
!isURL(url, {
|
||||
protocols: ['http', 'https'],
|
||||
/* eslint-disable camelcase, @typescript-eslint/naming-convention */
|
||||
require_tld: true,
|
||||
require_protocol: true
|
||||
/* eslint-enable camelcase, @typescript-eslint/naming-convention */
|
||||
});
|
||||
const {
|
||||
isButtonDisabled,
|
||||
title: { titleState, titleMessage },
|
||||
url: { urlState, urlMessage },
|
||||
image: { imageState, imageMessage },
|
||||
desc: { descriptionState, descriptionMessage },
|
||||
pristine
|
||||
} = this.formCorrect(portfolio);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>, id: string) => {
|
||||
e.preventDefault();
|
||||
if (isDisabled) return null;
|
||||
if (isButtonDisabled) return null;
|
||||
return this.updateItem(id);
|
||||
};
|
||||
|
||||
@@ -289,9 +308,9 @@ class PortfolioSettings extends Component<PortfolioProps, PortfolioState> {
|
||||
) : null}
|
||||
</FormGroup>
|
||||
<BlockSaveButton
|
||||
aria-disabled={isDisabled}
|
||||
aria-disabled={isButtonDisabled}
|
||||
bgSize='lg'
|
||||
{...(isDisabled && { tabIndex: -1 })}
|
||||
{...(isButtonDisabled && { tabIndex: -1 })}
|
||||
>
|
||||
{t('buttons.save-portfolio')}
|
||||
</BlockSaveButton>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
describe('Add Portfolio Item', () => {
|
||||
before(() => {
|
||||
cy.login();
|
||||
});
|
||||
|
||||
it('should be possible to add a portfolio item', () => {
|
||||
cy.visit('/settings');
|
||||
cy.contains('Add a new portfolio Item').click();
|
||||
|
||||
cy.get('.help-block').contains('A title is required');
|
||||
cy.get('[id$="title"]').type('This is a portfolio item');
|
||||
cy.get('button').filter(':disabled').should('have.length.gt', 0);
|
||||
|
||||
cy.get('[id$="url"]').type('This is a portfolio item');
|
||||
cy.get('.help-block').contains('URL must start with http or https');
|
||||
cy.get('[id$="url"]').clear().type('http://google.com');
|
||||
|
||||
cy.get('[id$="image"]').type('hello');
|
||||
cy.get('.help-block').contains('URL must start with http or https');
|
||||
cy.get('[id$="image"]')
|
||||
.clear()
|
||||
.type(
|
||||
'https://cdn.freecodecamp.org/curriculum/cat-photo-app/lasagna.jpg'
|
||||
);
|
||||
|
||||
cy.get('[id$="description"]').type(
|
||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod metus velit, vel accumsan lorem facilisis ac. Maecenas vitae ultrices dolor. Fusce in lobortis arcu, vel congue risus. Sed id neque nec nibh hendrerit bibendum. Integer venenatie.'
|
||||
);
|
||||
cy.get('.help-block').contains(
|
||||
'There is a maximum limit of 288 characters, you have 40 left'
|
||||
);
|
||||
|
||||
cy.get('[id$="description"]').type(
|
||||
'Lorem ipsum dolor sit amet, consecteturs.'
|
||||
);
|
||||
cy.get('.help-block').contains(
|
||||
'There is a maximum limit of 288 characters, you have 0 left'
|
||||
);
|
||||
cy.get('button').filter(':disabled').should('have.length.gt', 0);
|
||||
|
||||
cy.get('[id$="description"]').type('{backspace}');
|
||||
cy.get('button[type=submit]').contains('Save this portfolio item').click();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user