From bf1151d7d3c06a65ed69540363ebd67441143513 Mon Sep 17 00:00:00 2001 From: Vitaliy Kormylo Date: Sun, 1 Dec 2024 13:41:34 +0200 Subject: [PATCH 1/5] Fixed invalid additionalInfo validation in enroll offer modal --- src/components/app-text-area/AppTextArea.tsx | 7 ++- .../translations/en/offer-details-page.json | 5 +- .../translations/uk/offer-details-page.json | 5 +- .../enroll-offer/EnrollOffer.styles.ts | 4 ++ .../enroll-offer/EnrollOffer.tsx | 50 +++++++++++++++---- 5 files changed, 57 insertions(+), 14 deletions(-) diff --git a/src/components/app-text-area/AppTextArea.tsx b/src/components/app-text-area/AppTextArea.tsx index 927bae821..38f961f07 100644 --- a/src/components/app-text-area/AppTextArea.tsx +++ b/src/components/app-text-area/AppTextArea.tsx @@ -50,7 +50,12 @@ const AppTextArea: FC = ({ /> {maxLength && ( diff --git a/src/constants/translations/en/offer-details-page.json b/src/constants/translations/en/offer-details-page.json index 18c796f41..b9a09452d 100644 --- a/src/constants/translations/en/offer-details-page.json +++ b/src/constants/translations/en/offer-details-page.json @@ -35,5 +35,8 @@ "offerBanner": { "saveOfferButton": "Save Offer" }, - "closeOffer": "Are you sure that you want to close this offer? You can't reopen this offer." + "closeOffer": "Are you sure that you want to close this offer? You can't reopen this offer.", + "errors": { + "additionalInfo": "Additional information cannot be shorter than 30 symbols" + } } diff --git a/src/constants/translations/uk/offer-details-page.json b/src/constants/translations/uk/offer-details-page.json index 558415efb..ec4fc1390 100644 --- a/src/constants/translations/uk/offer-details-page.json +++ b/src/constants/translations/uk/offer-details-page.json @@ -35,5 +35,8 @@ "offerBanner": { "saveOfferButton": "Зберегти пропозицію" }, - "closeOffer": "Ви впевнені, що бажаєте закрити цю пропозицію? Ви не можете повторно відкрити цю пропозицію." + "closeOffer": "Ви впевнені, що бажаєте закрити цю пропозицію? Ви не можете повторно відкрити цю пропозицію.", + "errors": { + "additionalInfo": "Додаткова інформація не може бути коротшою за 30 символів" + } } diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts b/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts index b6bd352d0..27307840d 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts @@ -36,5 +36,9 @@ export const styles = { p: '12px 24px', width: { xs: '100%', sm: 'fit-content' }, minWidth: '280px' + }, + errorText: { + ml: '12.5px', + mt: '-17px' } } diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx index 3b2138b1e..0a3faf5bb 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx @@ -26,10 +26,13 @@ import { ErrorResponse, Offer, EnrollOfferForm, - ButtonTypeEnum + ButtonTypeEnum, + TypographyVariantEnum } from '~/types' import { openAlert } from '~/redux/features/snackbarSlice' import { getErrorKey } from '~/utils/get-error-key' +import { textField } from '~/utils/validations/common' +import { Typography } from '@mui/material' interface EnrollOfferProps { offer: Offer @@ -80,16 +83,32 @@ const EnrollOffer: FC = ({ offer, enrollOffer }) => { onResponseError: handleResponseError }) - const { data, handleInputChange, handleNonInputValueChange, handleSubmit } = - useForm({ - initialValues: { - proficiencyLevel: offer.proficiencyLevel[0], - price: offer.price, - additionalInfo: '', - title: offer.title - }, - onSubmit: fetchData - }) + const validateAdditionalInfo = (additionalInfoValue: string) => { + if (additionalInfoValue.length < 30 && additionalInfoValue.length !== 0) { + return textField(30, 1000) + } + } + + const validations = { + additionalInfo: validateAdditionalInfo + } + + const { + data, + errors, + handleInputChange, + handleNonInputValueChange, + handleSubmit + } = useForm({ + initialValues: { + proficiencyLevel: offer.proficiencyLevel[0], + price: offer.price, + additionalInfo: '', + title: offer.title + }, + validations: validations, + onSubmit: fetchData + }) const levelOptions = offer.proficiencyLevel.map((level) => ({ title: level, @@ -144,6 +163,15 @@ const EnrollOffer: FC = ({ offer, enrollOffer }) => { title={t('offerDetailsPage.enrollOffer.inputs.info')} value={data.additionalInfo} /> + {errors.additionalInfo && ( + + {t('offerDetailsPage.errors.additionalInfo')} + + )} Date: Sun, 1 Dec 2024 14:24:25 +0200 Subject: [PATCH 2/5] Fixed code coverage --- .../enroll-offer/EnrollOffer.spec.jsx | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx b/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx index 5ad675b24..5fc20b69d 100644 --- a/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx +++ b/tests/unit/containers/offer-details/enroll-offer/EnrollOffer.spec.jsx @@ -35,6 +35,25 @@ describe('EnrollOffer', () => { expect(levelSelect.value).toBe(newLevel) }) + it('should display error message', () => { + const newAdditionalInfo = 'Some text' + const additionalInfoInput = screen.getByLabelText( + 'offerDetailsPage.enrollOffer.labels.info' + ) + fireEvent.change(additionalInfoInput, { + target: { value: newAdditionalInfo } + }) + expect(additionalInfoInput.value).toBe(newAdditionalInfo) + + const button = screen.getByText('button.createCooperation') + waitFor(() => fireEvent.click(button)) + + const errorMessage = screen.getByText( + 'offerDetailsPage.errors.additionalInfo' + ) + expect(errorMessage).toBeInTheDocument() + }) + it('should send form', () => { const button = screen.getByText('button.createCooperation') From 14a52c3e096bd44197bb44b0a1c6482eaa0f1422 Mon Sep 17 00:00:00 2001 From: Vitaliy Kormylo Date: Sun, 1 Dec 2024 14:56:22 +0200 Subject: [PATCH 3/5] Refactored code for better clarity --- src/components/app-text-area/AppTextArea.tsx | 14 ++++--- .../enroll-offer/EnrollOffer.styles.ts | 2 +- .../enroll-offer/EnrollOffer.tsx | 39 ++++++++++--------- 3 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/components/app-text-area/AppTextArea.tsx b/src/components/app-text-area/AppTextArea.tsx index 38f961f07..0d85661bd 100644 --- a/src/components/app-text-area/AppTextArea.tsx +++ b/src/components/app-text-area/AppTextArea.tsx @@ -13,6 +13,7 @@ import { styles } from '~/components/app-text-area/AppTextArea.styles' interface AppTextAreaProps extends Omit { maxLength?: number + minLength?: number errorMsg?: string value?: string textFieldStyles?: SxProps @@ -24,6 +25,7 @@ const AppTextArea: FC = ({ minRows = 4, maxRows = 4, maxLength, + minLength, title, value, sx, @@ -35,6 +37,11 @@ const AppTextArea: FC = ({ const textLengthStyle = isRightAligned ? styles.textLengthRight : styles.textLength + let isLengthValid = value?.length === maxLength ? 'error' : 'primary.300' + isLengthValid = + minLength && value?.length < minLength && value?.length !== 0 + ? 'error' + : 'primary.300' return ( @@ -50,12 +57,7 @@ const AppTextArea: FC = ({ /> {maxLength && ( diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts b/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts index 27307840d..af402419c 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.styles.ts @@ -39,6 +39,6 @@ export const styles = { }, errorText: { ml: '12.5px', - mt: '-17px' + mt: '3px' } } diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx index 0a3faf5bb..a9fd18721 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx @@ -154,24 +154,27 @@ const EnrollOffer: FC = ({ offer, enrollOffer }) => { onChange={handleFieldChange('price')} title={t('offerDetailsPage.enrollOffer.labels.preferredPrice')} /> - - {errors.additionalInfo && ( - - {t('offerDetailsPage.errors.additionalInfo')} - - )} + + + {errors.additionalInfo && ( + + {t('offerDetailsPage.errors.additionalInfo')} + + )} + Date: Sun, 1 Dec 2024 15:07:59 +0200 Subject: [PATCH 4/5] Fixed some ternary operators --- src/components/app-text-area/AppTextArea.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/app-text-area/AppTextArea.tsx b/src/components/app-text-area/AppTextArea.tsx index 0d85661bd..4f0e6fa1c 100644 --- a/src/components/app-text-area/AppTextArea.tsx +++ b/src/components/app-text-area/AppTextArea.tsx @@ -37,11 +37,11 @@ const AppTextArea: FC = ({ const textLengthStyle = isRightAligned ? styles.textLengthRight : styles.textLength - let isLengthValid = value?.length === maxLength ? 'error' : 'primary.300' - isLengthValid = + const isLengthTooShort = minLength && value?.length < minLength && value?.length !== 0 - ? 'error' - : 'primary.300' + const isLengthTooLong = value?.length === maxLength + const isLengthValid = + isLengthTooShort || isLengthTooLong ? 'error' : 'primary.300' return ( From 35314ba98f7778a0957ef348b7391c834031966f Mon Sep 17 00:00:00 2001 From: Vitaliy Kormylo Date: Tue, 3 Dec 2024 20:51:13 +0200 Subject: [PATCH 5/5] Fixed incorrect empty addtionalInfo sending in request --- src/containers/offer-details/enroll-offer/EnrollOffer.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx index a9fd18721..21a2d23fd 100644 --- a/src/containers/offer-details/enroll-offer/EnrollOffer.tsx +++ b/src/containers/offer-details/enroll-offer/EnrollOffer.tsx @@ -84,6 +84,9 @@ const EnrollOffer: FC = ({ offer, enrollOffer }) => { }) const validateAdditionalInfo = (additionalInfoValue: string) => { + if (additionalInfoValue.length === 0) { + delete data.additionalInfo + } if (additionalInfoValue.length < 30 && additionalInfoValue.length !== 0) { return textField(30, 1000) }