From f578a22c999c50e766e4a243e7ed40418a776534 Mon Sep 17 00:00:00 2001 From: Sem Bauke Date: Fri, 17 Mar 2023 12:27:53 +0100 Subject: [PATCH] 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 --- client/src/components/settings/portfolio.tsx | 105 +++++++++++-------- cypress/e2e/default/settings/portfolio.ts | 44 ++++++++ 2 files changed, 106 insertions(+), 43 deletions(-) create mode 100644 cypress/e2e/default/settings/portfolio.ts diff --git a/client/src/components/settings/portfolio.tsx b/client/src/components/settings/portfolio.tsx index 15d8353ea35..79498e4033f 100644 --- a/client/src/components/settings/portfolio.tsx +++ b/client/src/components/settings/portfolio.tsx @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/naming-convention */ import { Button, FormGroup, @@ -120,25 +121,6 @@ class PortfolioSettings extends Component { 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 { : { 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 { ) => { 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, id: string) => { e.preventDefault(); - if (isDisabled) return null; + if (isButtonDisabled) return null; return this.updateItem(id); }; @@ -289,9 +308,9 @@ class PortfolioSettings extends Component { ) : null} {t('buttons.save-portfolio')} diff --git a/cypress/e2e/default/settings/portfolio.ts b/cypress/e2e/default/settings/portfolio.ts new file mode 100644 index 00000000000..ea31efd2137 --- /dev/null +++ b/cypress/e2e/default/settings/portfolio.ts @@ -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(); + }); +});