Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: address field #7966

Draft
wants to merge 22 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions __tests__/unit/backend/helpers/generate-form-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,12 @@ export const generateNewSingleAnswerResponse = (
customParams?: Partial<ProcessedSingleAnswerResponse>,
): ProcessedSingleAnswerResponse => {
if (
[BasicField.Attachment, BasicField.Table, BasicField.Checkbox].includes(
fieldType,
)
[
BasicField.Attachment,
BasicField.Table,
BasicField.Checkbox,
BasicField.Address,
].includes(fieldType)
) {
throw new Error(
'Call the custom response generator functions for attachment, table and checkbox.',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useToast } from '~hooks/useToast'
import IconButton from '~components/IconButton'
import Tooltip from '~components/Tooltip'
import {
AddressCompoundField,
AttachmentField,
CheckboxField,
ChildrenCompoundField,
Expand Down Expand Up @@ -512,5 +513,7 @@ const FieldRow = ({ field, ...rest }: FieldRowProps) => {
return <TableField schema={field} {...rest} />
case BasicField.Children:
return <ChildrenCompoundField schema={field} {...rest} />
case BasicField.Address:
return <AddressCompoundField schema={field} {...rest} />
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
EditMyInfoChildren,
} from './edit-fieldtype/EditMyInfoChildren'
import {
EditAddress,
EditAttachment,
EditCheckbox,
EditCountryRegion,
Expand Down Expand Up @@ -167,6 +168,8 @@ export const MemoFieldDrawerContent = memo<MemoFieldDrawerContentProps>(
return <EditParagraph {...props} field={field} />
case BasicField.Image:
return <EditImage {...props} field={field} />
case BasicField.Address:
return <EditAddress {...props} field={field} />
default:
return <div>TODO: Insert field options here</div>
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Meta, StoryFn } from '@storybook/react'

import { AddressCompoundFieldBase, BasicField } from '~shared/types'

import { createFormBuilderMocks } from '~/mocks/msw/handlers/admin-form'

import { EditFieldDrawerDecorator, StoryRouter } from '~utils/storybook'

import { EditAddress, EditAddressProps } from './EditAddress'

const DEFAULT_ADDRESS_FIELD: AddressCompoundFieldBase = {
title: 'Local address',
description: '',
required: true,
disabled: false,
fieldType: BasicField.Address,
globalId: 'unused',
}

export default {
title: 'Features/AdminForm/EditFieldDrawer/EditAddress',
component: EditAddress,
decorators: [
StoryRouter({
initialEntries: ['/61540ece3d4a6e50ac0cc6ff'],
path: '/:formId',
}),
EditFieldDrawerDecorator,
],
parameters: {
// Required so skeleton "animation" does not hide content.
chromatic: { pauseAnimationAtEnd: true },
msw: createFormBuilderMocks({}, 0),
},
args: {
field: DEFAULT_ADDRESS_FIELD,
},
} as Meta<EditAddressProps>

interface StoryArgs {
field: AddressCompoundFieldBase
}

const Template: StoryFn<StoryArgs> = ({ field }) => {
return <EditAddress field={field} />
}

export const Default = Template.bind({})

export const WithValues = Template.bind({})
WithValues.args = {
field: {
...DEFAULT_ADDRESS_FIELD,
title: 'Address Field Title',
description: 'Address Field Description',
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { useMemo } from 'react'
import { FormControl } from '@chakra-ui/react'
import { extend, pick } from 'lodash'

import { AddressCompoundFieldBase } from '~shared/types/field'

import { createBaseValidationRules } from '~utils/fieldValidation'
import FormErrorMessage from '~components/FormControl/FormErrorMessage'
import FormLabel from '~components/FormControl/FormLabel'
import Input from '~components/Input'
import Textarea from '~components/Textarea'
import Toggle from '~components/Toggle'

import { CreatePageDrawerContentContainer } from '~features/admin-form/create/common'

import { FormFieldDrawerActions } from '../common/FormFieldDrawerActions'
import { EditFieldProps } from '../common/types'
import { useEditFieldForm } from '../common/useEditFieldForm'

export type EditAddressProps = EditFieldProps<AddressCompoundFieldBase>

type EditAddressInputs = Pick<
AddressCompoundFieldBase,
'title' | 'description' | 'required'
>

export const EditAddress = ({ field }: EditAddressProps): JSX.Element => {
const {
register,
formState: { errors },
getValues,
buttonText,
handleUpdateField,
watch,
control,
clearErrors,
isLoading,
handleCancel,
setValue,
} = useEditFieldForm<EditAddressInputs, AddressCompoundFieldBase>({
field,
transform: {
input: (inputField) =>
pick(inputField, ['title', 'description', 'required']),
output: (formOutput, originalField) =>
extend({}, originalField, formOutput),
},
})

const requiredValidationRule = useMemo(
() => createBaseValidationRules({ required: true }),
[],
)
return (
<CreatePageDrawerContentContainer>
<FormControl isRequired isReadOnly={isLoading} isInvalid={!!errors.title}>
<FormLabel>Field Name</FormLabel>
<Input autoFocus {...register('title', requiredValidationRule)} />
<FormErrorMessage>{errors?.title?.message}</FormErrorMessage>
</FormControl>
<FormControl isReadOnly={isLoading} isInvalid={!!errors.description}>
<FormLabel>Description</FormLabel>
<Textarea {...register('description')} />
<FormErrorMessage>{errors?.description?.message}</FormErrorMessage>
</FormControl>
<FormControl isReadOnly={isLoading}>
<Toggle {...register('required')} label="Required" />
</FormControl>
<FormFieldDrawerActions
isLoading={isLoading}
buttonText={buttonText}
handleClick={handleUpdateField}
handleCancel={handleCancel}
/>
</CreatePageDrawerContentContainer>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { EditAddress } from './EditAddress'
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './EditAddress'
export * from './EditAttachment'
export * from './EditCheckbox'
export * from './EditCountryRegion'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const BASIC_FIELDS_ORDERED = [
BasicField.Email,
BasicField.Mobile,
BasicField.HomeNo,
BasicField.Address,
BasicField.Date,
BasicField.Image,
BasicField.Table,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,12 @@ export const getFieldCreationMeta = (fieldType: BasicField): FieldCreateDto => {
...baseMeta,
}
}
case BasicField.Address: {
return {
fieldType,
...baseMeta,
}
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions frontend/src/features/admin-form/create/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import {
BiUser,
BiUserVoice,
} from 'react-icons/bi'
import { SlLocationPin } from 'react-icons/sl'
import { As } from '@chakra-ui/react'

import { BasicField, MyInfoAttribute } from '~shared/types/field'
Expand Down Expand Up @@ -266,6 +267,12 @@ export const BASICFIELD_TO_DRAWER_META: {
icon: BiGroup,
isSubmitted: true,
},

[BasicField.Address]: {
label: 'Local address',
icon: SlLocationPin,
isSubmitted: true,
Copy link
Contributor

@KenLSM KenLSM Dec 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/nit Regarding searchAliases: to get input from Ruchel + Kenneth before we release.

},
}

const BiDummyIcon = BiCalendar // random icon that is not actually shown in app
Expand Down
1 change: 0 additions & 1 deletion frontend/src/features/public-form/PublicFormProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,6 @@ const transformFormInputCountryRegionToUpperCase =
.filter((field) => field.fieldType === BasicField.CountryRegion)
.map((field) => field._id),
)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accidental change here? It should be fine to leave a visual break here.

return Object.keys(formInputs).reduce(
(newFormInputs: typeof formInputs, fieldId) => {
const currentInput = formInputs[fieldId]
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/features/public-form/PublicFormService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@ export const submitEmailModeForm = async ({
formInputs: filteredInputs,
responseMetadata,
})

return ApiService.post<SubmissionResponseDto>(
`${PUBLIC_FORMS_ENDPOINT}/${formId}/submissions/email`,
formData,
Expand Down Expand Up @@ -272,7 +271,6 @@ export const submitStorageModeForm = async ({
formInputs,
formLogics,
})

const formData = createClearSubmissionWithVirusScanningFormData(
{
formFields,
Expand All @@ -285,7 +283,9 @@ export const submitStorageModeForm = async ({
},
fieldIdToQuarantineKeyMap,
)

console.log('here i am')
console.log(formFields)
console.log(formData.get('body'))
return ApiService.post<SubmissionResponseDto>(
`${PUBLIC_FORMS_ENDPOINT}/${formId}/submissions/storage`,
formData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BasicField } from '~shared/types/field'
import { FormColorTheme, FormResponseMode } from '~shared/types/form'

import {
AddressCompoundField,
AttachmentField,
CheckboxField,
ChildrenCompoundField,
Expand Down Expand Up @@ -119,6 +120,8 @@ export const FieldFactory = memo(
return <ImageField schema={field} {...rest} />
case BasicField.Table:
return <TableField schema={field} {...rest} />
case BasicField.Address:
return <AddressCompoundField schema={field} {...rest} />
case BasicField.Children:
return (
<ChildrenCompoundField
Expand Down
13 changes: 12 additions & 1 deletion frontend/src/features/public-form/utils/createSubmission.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export const createClearSubmissionWithVirusScanningFormData = (
return response
},
)

const attachments = getAttachmentsMap(formFields, formInputs)

// Convert content to FormData object.
Expand All @@ -174,7 +175,6 @@ export const createClearSubmissionWithVirusScanningFormData = (
...formDataArgsRest,
}),
)

if (!isEmpty(attachments)) {
forOwn(attachments, (attachment, fieldId) => {
if (attachment) {
Expand Down Expand Up @@ -281,6 +281,17 @@ const createResponsesV3 = (
} as FieldResponseV3
break
}
case BasicField.Address: {
const input = formInputs[ff._id] as
| FormFieldValue<typeof ff.fieldType>
| undefined
if (!input) break
returnedInputs[ff._id] = {
fieldType: ff.fieldType,
answer: input,
} as FieldResponseV3
break
}
case BasicField.Email:
case BasicField.Mobile: {
const input = formInputs[ff._id] as
Expand Down
36 changes: 35 additions & 1 deletion frontend/src/features/public-form/utils/inputTransformation.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Address } from 'cluster'
import { format, parse } from 'date-fns'
import { times } from 'lodash'

import { DATE_PARSE_FORMAT } from '~shared/constants/dates'
import {
AddressCompoundFieldResponseV3,
AttachmentFieldResponseV3,
CheckboxFieldResponsesV3,
ChildrenCompoundFieldResponsesV3,
Expand All @@ -12,8 +14,14 @@ import {
VerifiableFieldResponseV3,
YesNoFieldResponseV3,
} from '~shared/types'
import { BasicField, FormFieldDto } from '~shared/types/field'
import {
AddressAttributes,
BasicField,
FormFieldDto,
} from '~shared/types/field'
import {
AddressResponse,
AddressSubField,
AttachmentResponse,
CheckboxResponse,
ChildBirthRecordsResponse,
Expand All @@ -29,6 +37,8 @@ import { CHECKBOX_OTHERS_INPUT_VALUE } from '~templates/Field/Checkbox/constants
import { RADIO_OTHERS_INPUT_VALUE } from '~templates/Field/Radio/constants'
import { createTableRow } from '~templates/Field/Table/utils/createRow'
import {
AddressCompoundFieldSchema,
AddressCompoundFieldValues,
AttachmentFieldSchema,
BaseFieldOutput,
CheckboxFieldSchema,
Expand Down Expand Up @@ -217,6 +227,25 @@ const transformToChildOutput = (
}
}

const transformToAddressOutput = (
schema: AddressCompoundFieldSchema,
input?: AddressCompoundFieldValues | AddressCompoundFieldResponseV3,
): AddressResponse => {
console.log(input?.addressSubFields)
// const answerArray: AddressSubField[] = []
const answerArray: string[][] = []
if (input !== undefined) {
Object.entries(input.addressSubFields).map(([key, value]) => {
// answerArray.push({ key: key, value: value })
answerArray.push([`${key}:${value}`])
})
}
return {
...pickBaseOutputFromSchema(schema),
answerArray,
}
}

type FormFieldValueOrFieldResponseAnswerV3<T extends BasicField> =
| FormFieldValue<T>
| FieldResponseAnswerMapV3<T>
Expand Down Expand Up @@ -296,5 +325,10 @@ export const transformInputsToOutputs = (
field,
input as FormFieldValueOrFieldResponseAnswerV3<typeof field.fieldType>,
)
case BasicField.Address:
return transformToAddressOutput(
field,
input as FormFieldValueOrFieldResponseAnswerV3<typeof field.fieldType>,
)
}
}
Loading
Loading