Skip to content

Commit 19e4099

Browse files
authored
Create campaign application - fixes (#2002)
* feat: campaign application fixes - move the field cause (aka goal - "за какво са нужни средствата") down as per request from team campaigns - add a "at least one document" hint to the document - make the beneficiary relationship required (as it is on the API side) - add validation error for not accepted terms - add validation for missing document - reset touched state after first step b/c that first step's submit makes all fields on steps 2 and 3 touched and shows errors immediately * chore: update e2e tests
1 parent bbea44a commit 19e4099

File tree

13 files changed

+72
-24
lines changed

13 files changed

+72
-24
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,9 @@ Watch releases of this repository to be notified about future updates:
100100
## Contributors ✨
101101

102102
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
103+
103104
[![All Contributors](https://img.shields.io/badge/all_contributors-87-orange.svg?style=flat-square)](#contributors-)
105+
104106
<!-- ALL-CONTRIBUTORS-BADGE:END -->
105107

106108
Please check [contributors guide](https://github.com/podkrepi-bg/frontend/blob/master/CONTRIBUTING.md) for:

e2e/tests/regression/campaign-application/campaign-application-admin.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,6 @@ function camAppForEdit(): CampaignApplicationExisting {
165165
acceptTermsAndConditions: true,
166166
transparencyTermsAccepted: true,
167167
personalInformationProcessingAccepted: true,
168-
documents: [],
168+
documents: [{ filename: 'test.me', id: 'test.me' }],
169169
}
170170
}

e2e/tests/regression/campaign-application/campaign-application-giver.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ test.describe('Campaign application giver', () => {
1313

1414
// assert
1515
const t = await textLocalized().campaign.bg()
16-
await expect(page.getByRole('heading')).toHaveText(t.steps.organizer.title)
16+
await expect(page.getByRole('heading', { name: t.steps.organizer.title })).toBeVisible()
1717

1818
await page.getByRole('checkbox').first().click()
1919
await page.getByRole('checkbox').nth(1).click()
@@ -22,7 +22,7 @@ test.describe('Campaign application giver', () => {
2222
await page.getByRole('button', { name: t.cta.next }).click()
2323

2424
// assert
25-
await expect(page.getByRole('heading')).toHaveText(t.steps.application.title)
25+
await expect(page.getByRole('heading', { name: t.steps.application.title })).toBeVisible()
2626
})
2727

2828
test('should see the second step -application - of create campaign application wizard and after filling in the beneficiary, relations, title, type and funds go to step 3', async ({
@@ -55,7 +55,7 @@ test.describe('Campaign application giver', () => {
5555
await page.getByRole('button', { name: t.cta.next }).click()
5656

5757
// assert
58-
await expect(page.getByRole('heading')).toHaveText(t.steps.details.title)
58+
await expect(page.getByRole('heading', { name: t.steps.details.title })).toBeVisible()
5959
})
6060

6161
test('should see the third step - details - of create campaign application wizard and after filling the title, description, history and 2 files be able to create a new campaign application', async ({

public/locales/bg/campaign-application.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
},
4242
"photos": "Снимков/видео материал",
4343
"documents": "Документи",
44-
"disclaimer": "Приемат се до 10 документа. Всеки от документите може да бъде до 30МБ"
44+
"disclaimer": "Приемат се до 10 документа. Всеки от документите може да бъде до 30МБ",
45+
"documents-hint": "Моля, приложете поне един документ в подкрепа на нуждата ви, като например: медицинска документация, оферти за ремонт, обучение или лечение, писма или становища от институции, детайлен бюджет, оферти за необходими артикули или услуги, както и други документи, свързани с каузата ви."
4546
},
4647
"admin": {
4748
"title": "Администраторска редакция",

public/locales/en/campaign-application.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
},
4242
"photos": "Photo/Video material",
4343
"documents": "Documents",
44-
"disclaimer": "Up to 10 documents accepted. Each of the documents can be up to 30MB is size"
44+
"disclaimer": "Up to 10 documents accepted. Each of the documents can be up to 30MB is size",
45+
"documents-hint": "Please attach at least one document to stake your claim like: medical documents, offers for repair learning or healthcare, letters from institutions, detailed budget, offers for required items or services, as well as any other documents to do with your cause."
4546
},
4647
"admin": {
4748
"title": "Admin edit",

src/components/client/campaign-application/CampaignApplicationForm.tsx

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ export default function CampaignApplicationForm({
8484

8585
const handleSubmit = async (
8686
formData: CampaignApplicationFormData,
87-
{ resetForm }: FormikHelpers<CampaignApplicationFormData>,
87+
{ resetForm, setTouched }: FormikHelpers<CampaignApplicationFormData>,
8888
) => {
8989
if (activeStep === Steps.CREATED_DETAILS && camApp?.id != null) {
9090
router.push(routes.campaigns.applicationEdit(camApp?.id)) // go to the edit page
@@ -100,6 +100,26 @@ export default function CampaignApplicationForm({
100100
}
101101
} else {
102102
setActiveStep((prevActiveStep) => prevActiveStep + 1)
103+
104+
// reset the touched state b/c every step gets "submitted" in terms of formik and that in turn marks all values as touched
105+
// the effect is that every step after the first immediately marks all required fields as errored even before the user has touched them
106+
setTouched({
107+
applicationDetails: {
108+
description: false,
109+
currentStatus: false,
110+
cause: false,
111+
documents: false,
112+
},
113+
applicationBasic: {
114+
beneficiaryNames: false,
115+
title: false,
116+
campaignType: false,
117+
funds: false,
118+
campaignEnd: false,
119+
campaignEndDate: false,
120+
organizerBeneficiaryRelationship: false,
121+
},
122+
})
103123
}
104124
}
105125

src/components/client/campaign-application/helpers/campaignApplication.types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ export type CampaignApplicationBasic = {
2626
funds: number
2727
campaignEnd: string
2828
campaignEndDate?: string
29+
organizerBeneficiaryRelationship?: string
2930
}
3031

3132
export type CampaignApplicationDetails = {
3233
cause: string
33-
organizerBeneficiaryRelationship?: string
3434
description?: string
3535
currentStatus?: string
36+
documents?: File[]
3637
}
3738

3839
// keep in sync with api repo/podkrepi.dbml -> Enum CampaignApplicationState

src/components/client/campaign-application/helpers/validation-schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,16 +31,16 @@ const basicSchema: yup.SchemaOf<CampaignApplicationBasic> = yup.object().shape({
3131
funds: yup.number().required(),
3232
title: yup.string().required(),
3333
campaignEndDate: yup.string().optional(),
34+
organizerBeneficiaryRelationship: yup.string().required(),
3435
})
3536

3637
const detailsSchema: yup.SchemaOf<CampaignApplicationDetails> = yup.object().shape({
3738
cause: yup.string().required(),
3839
campaignGuarantee: yup.string().optional(),
3940
currentStatus: yup.string().optional(),
4041
description: yup.string().optional(),
41-
documents: yup.array().optional(),
42+
documents: yup.array().min(1, 'documents-hint').required(),
4243
links: yup.array().optional(),
43-
organizerBeneficiaryRelationship: yup.string().optional(),
4444
otherFinancialSources: yup.string().optional(),
4545
})
4646

src/components/client/campaign-application/steps/CampaignApplicationBasic.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export default function CampaignApplicationBasic() {
4747
<StyledFormTextField
4848
label={t('steps.application.beneficiaryRelationship')}
4949
type="text"
50-
name="applicationDetails.organizerBeneficiaryRelationship"
50+
name="applicationBasic.organizerBeneficiaryRelationship"
5151
/>
5252
</Grid>
5353
<Grid item xs={12}>

src/components/client/campaign-application/steps/CampaignApplicationDetails.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
import { Grid, Typography } from '@mui/material'
1+
import { FormControl, FormHelperText, Grid, Typography } from '@mui/material'
22
import { useTranslation } from 'next-i18next'
33

44
import FormTextField from 'components/common/form/FormTextField'
55
import { StyledStepHeading } from '../helpers/campaignApplication.styled'
66

77
import FileList from 'components/common/file-upload/FileList'
88
import FileUpload from 'components/common/file-upload/FileUpload'
9-
import { Dispatch, SetStateAction } from 'react'
9+
import { Dispatch, SetStateAction, useEffect } from 'react'
10+
import { useFormikContext } from 'formik'
11+
import { CampaignApplicationFormData } from '../helpers/campaignApplication.types'
1012

1113
export type Props = {
1214
files: File[]
@@ -15,6 +17,11 @@ export type Props = {
1517

1618
export default function CampaignApplicationDetails({ files, setFiles }: Props) {
1719
const { t } = useTranslation('campaign-application')
20+
const { setFieldValue, errors, touched } = useFormikContext<CampaignApplicationFormData>()
21+
22+
useEffect(() => {
23+
setFieldValue('applicationDetails.documents', files, false)
24+
}, [files])
1825

1926
return (
2027
<Grid container spacing={6} justifyContent="center" direction="column" alignContent="center">
@@ -51,13 +58,20 @@ export default function CampaignApplicationDetails({ files, setFiles }: Props) {
5158
/>
5259
</Grid>
5360
<Grid item xs={12}>
54-
<FileUpload
55-
buttonLabel={t('steps.details.documents')}
56-
onUpload={(newFiles) => {
57-
setFiles((prevFiles) => [...prevFiles, ...newFiles])
58-
}}
59-
accept="text/plain,application/json,application/pdf,image/png,image/jpeg,application/xml,text/xml,application/msword,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
60-
/>
61+
<FormControl>
62+
<Typography variant="h6">{t('steps.details.documents-hint')}</Typography>
63+
<FileUpload
64+
buttonLabel={t('steps.details.documents')}
65+
onUpload={(newFiles) => {
66+
setFiles((prevFiles) => [...prevFiles, ...newFiles])
67+
setFieldValue('applicationDetails.documents', newFiles)
68+
}}
69+
accept="text/plain,application/json,application/pdf,image/png,image/jpeg,application/xml,text/xml,application/msword,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
70+
/>
71+
{touched.applicationDetails?.documents && errors.applicationDetails?.documents && (
72+
<FormHelperText error>{t('steps.details.documents-hint')}</FormHelperText>
73+
)}
74+
</FormControl>
6175
<Typography>{t('steps.details.disclaimer')}</Typography>
6276
<FileList
6377
files={files}

0 commit comments

Comments
 (0)