From 1b6c7b8ec901d1ba24b502dbcd110650356cb22e Mon Sep 17 00:00:00 2001 From: Jamil Date: Fri, 17 Jan 2025 19:46:38 +0600 Subject: [PATCH] feat: create address input (#362) * chore: update yarn.lock * feat: wip: birth event v2 * feat: use select option in gender, attendantAtBirth and birthType * fix: use number for weight at birth * feat: person input wip * feat: show dob or age based on dobUnknown checkbox * chore: rename directory * amend: import from renamed directory * feat: add informant relation to birth form * feat: render informant fields based on relation to child * feat: separate the logic for concatenating field id * feat: complete informant details apart form person inputs * feat: implement id and address * refactor: create utils * fix: handle undefined values in conditionals * feat: implement father and mother details * feat: implement upload supporting document * fix: use simpler concat * feat: use country field * feat: add place of birth * fix: typo * fix: align label and required properties with legecy birth * fix: font of bulletList * feat: add helper texts * chore: bump up @opencrvs/toolkit * chore: update yarn.lock * feat: use Location type in address * feat: implement urbanOrRural * feat: implement health_failities * feat: add addressInput in tennis-club-membership * fix: update ids of other country input fields * rename: BirthEvent to birthEvent * chore: remove the messages that are not in use * chore: remove unused * refactor: use informantType instead of hardcoding * refactor: birth event * chore: bump up toolkit * feat: add relation to child for someone else * feat: usual place of residence same as mother * refactor: make suggested changes * fix: update types --- src/form/tennis-club-membership.ts | 17 ++- src/form/v2/birth/forms/child.ts | 11 +- src/form/v2/birth/forms/declare.ts | 6 +- src/form/v2/birth/forms/informant.ts | 26 ++++- src/form/v2/person/address.ts | 132 +++++++++++++++++----- src/form/v2/person/index.ts | 157 ++++++++++++++++++++------- 6 files changed, 277 insertions(+), 72 deletions(-) diff --git a/src/form/tennis-club-membership.ts b/src/form/tennis-club-membership.ts index a77269eb5..ede50e298 100644 --- a/src/form/tennis-club-membership.ts +++ b/src/form/tennis-club-membership.ts @@ -21,6 +21,7 @@ import { field, deduplication } from '@opencrvs/toolkit/conditionals' +import { getAddressFields } from './v2/person/address' const TENNIS_CLUB_FORM = defineForm({ label: { @@ -112,7 +113,21 @@ const TENNIS_CLUB_FORM = defineForm({ description: 'This is the label for the field', id: 'event.tennis-club-membership.action.declare.form.section.who.field.image.label' } - } + }, + { + id: 'applicant.address.helper', + type: 'PARAGRAPH', + required: false, + label: { + defaultMessage: "Applicant's address", + description: 'This is the label for the field', + id: 'event.tennis-club-membership.action.declare.form.section.who.field.address.helper.label' + }, + options: { + fontVariant: 'h3' + } + }, + ...getAddressFields('applicant') ] }, { diff --git a/src/form/v2/birth/forms/child.ts b/src/form/v2/birth/forms/child.ts index 21f2a3f1b..d6fa1ead6 100644 --- a/src/form/v2/birth/forms/child.ts +++ b/src/form/v2/birth/forms/child.ts @@ -12,7 +12,7 @@ import { defineFormPage, TranslationConfig } from '@opencrvs/toolkit/events' import { field } from '@opencrvs/toolkit/conditionals' import { appendConditionalsToFields, createSelectOptions } from '../../utils' -import { getAddressFields } from '../../person/address' +import { AddressType, getAddressFields } from '../../person/address' const GenderTypes = { MALE: 'male', @@ -235,13 +235,16 @@ export const childPage = defineFormPage({ }, { id: 'child.birthLocation', - type: 'TEXT', // @ToDo: select + type: 'LOCATION', required: true, label: { defaultMessage: 'Health Institution', description: 'This is the label for the field', id: 'event.birth.action.declare.form.section.child.field.birthLocation.label' }, + options: { + type: 'HEALTH_FACILITY' + }, conditionals: [ { type: 'HIDE', @@ -252,7 +255,7 @@ export const childPage = defineFormPage({ ] }, ...appendConditionalsToFields({ - inputFields: getAddressFields('child.privateHome'), + inputFields: getAddressFields(AddressType.childResidentialAddress), newConditionals: [ { type: 'HIDE', @@ -263,7 +266,7 @@ export const childPage = defineFormPage({ ] }), ...appendConditionalsToFields({ - inputFields: getAddressFields('child.other'), + inputFields: getAddressFields(AddressType.childOther), newConditionals: [ { type: 'HIDE', diff --git a/src/form/v2/birth/forms/declare.ts b/src/form/v2/birth/forms/declare.ts index e5506d616..05d4e01ea 100644 --- a/src/form/v2/birth/forms/declare.ts +++ b/src/form/v2/birth/forms/declare.ts @@ -14,7 +14,7 @@ import { field, and } from '@opencrvs/toolkit/conditionals' import { childPage } from './child' import { informantPage, InformantTypes } from './informant' import { appendConditionalsToFields } from '../../utils' -import { getPersonInputFields } from '../../person' +import { getPersonInputFields, PersonType } from '../../person' export const BIRTH_DECLARE_FORM = defineForm({ label: { @@ -134,7 +134,7 @@ export const BIRTH_DECLARE_FORM = defineForm({ }, ...appendConditionalsToFields({ inputFields: [ - ...getPersonInputFields('mother'), + ...getPersonInputFields(PersonType.mother), { id: 'mother.previousBirths', type: 'TEXT', @@ -206,7 +206,7 @@ export const BIRTH_DECLARE_FORM = defineForm({ ] }, ...appendConditionalsToFields({ - inputFields: getPersonInputFields('father'), + inputFields: getPersonInputFields(PersonType.father), newConditionals: [ { type: 'HIDE', diff --git a/src/form/v2/birth/forms/informant.ts b/src/form/v2/birth/forms/informant.ts index 8437c1121..37c59a7ed 100644 --- a/src/form/v2/birth/forms/informant.ts +++ b/src/form/v2/birth/forms/informant.ts @@ -12,7 +12,8 @@ import { defineFormPage, TranslationConfig } from '@opencrvs/toolkit/events' import { field } from '@opencrvs/toolkit/conditionals' import { appendConditionalsToFields, createSelectOptions } from '../../utils' -import { getInformantFields } from '../../person' +import { getPersonInputCommonFields, PersonType } from '../../person' +import { getAddressFields } from '../../person/address' export const InformantTypes = { MOTHER: 'MOTHER', @@ -92,8 +93,29 @@ export const informantPage = defineFormPage({ }, options: birthInformantTypeOptions }, + { + id: 'informant.other.relation', + type: 'TEXT', + required: true, + label: { + defaultMessage: 'Relationship to child', + description: 'This is the label for the field', + id: 'event.birth.action.declare.form.section.informant.field.other.relation.label' + }, + conditionals: [ + { + type: 'HIDE', + conditional: field('informant.relation').isUndefinedOrNotInArray([ + InformantTypes.OTHER + ]) + } + ] + }, ...appendConditionalsToFields({ - inputFields: getInformantFields('informant'), + inputFields: [ + ...getPersonInputCommonFields(PersonType.informant), + ...getAddressFields(PersonType.informant) + ], newConditionals: [ { type: 'HIDE', diff --git a/src/form/v2/person/address.ts b/src/form/v2/person/address.ts index 1de79ce67..b91ff1fbe 100644 --- a/src/form/v2/person/address.ts +++ b/src/form/v2/person/address.ts @@ -9,12 +9,42 @@ * Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS. */ -import { FieldConfig } from '@opencrvs/toolkit/events' +import { FieldConfig, TranslationConfig } from '@opencrvs/toolkit/events' import { field } from '@opencrvs/toolkit/conditionals' -import { appendConditionalsToFields } from '../utils' +import { appendConditionalsToFields, createSelectOptions } from '../utils' +import { PersonType } from './index' -export const getAddressFields = (person: string): FieldConfig[] => { - // @Todo: Same as mother or deseased +export const AddressType = { + childResidentialAddress: 'childResidentialAddress', + childOther: 'childOther' +} as const + +export type AddressType = keyof typeof AddressType | PersonType + +const UrbanRuralTypes = { + URBAN: 'URBAN', + RURAL: 'RURAL' +} as const + +const urbanRuralMessageDescriptors = { + URBAN: { + defaultMessage: 'Urban', + id: 'form.field.label.urban', + description: 'Label for form field checkbox option Urban' + }, + RURAL: { + defaultMessage: 'Rural', + id: 'form.field.label.rural', + description: 'Label for form field checkbox option Rural' + } +} satisfies Record + +const urbanRuralRadioOptions = createSelectOptions( + UrbanRuralTypes, + urbanRuralMessageDescriptors +) + +export const getAddressFields = (person: AddressType): FieldConfig[] => { const prefix = `${person}.address` const genericAddressFields: FieldConfig[] = [ @@ -90,27 +120,7 @@ export const getAddressFields = (person: string): FieldConfig[] => { } ] - const farajalandAddressFields: FieldConfig[] = [ - { - id: `${prefix}.province`, - type: 'TEXT', - required: true, - label: { - defaultMessage: 'Province', - description: 'This is the label for the field', - id: `event.action.declare.form.section.person.field.address.province.label` - } - }, - { - id: `${prefix}.district`, - type: 'TEXT', - required: true, - label: { - defaultMessage: 'District', - description: 'This is the label for the field', - id: `event.action.declare.form.section.person.field.address.district.label` - } - }, + const urbanAddressFields: FieldConfig[] = [ { id: `${prefix}.town`, type: 'TEXT', @@ -162,6 +172,78 @@ export const getAddressFields = (person: string): FieldConfig[] => { } } ] + const farajalandAddressFields: FieldConfig[] = [ + { + id: `${prefix}.province`, + type: 'LOCATION', + required: true, + label: { + defaultMessage: 'Province', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.address.province.label` + }, + options: { + type: 'ADMIN_STRUCTURE' + } + }, + { + id: `${prefix}.district`, + type: 'LOCATION', + required: true, + label: { + defaultMessage: 'District', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.address.district.label` + }, + options: { + partOf: { + $data: `${prefix}.province` + }, + type: 'ADMIN_STRUCTURE' + } + }, + { + id: `${prefix}.urbanOrRural`, + type: 'RADIO_GROUP', + options: urbanRuralRadioOptions, + flexDirection: 'row', + required: false, + label: { + defaultMessage: 'Urban or Rural', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.address.urbanOrRural.label` + } + }, + ...appendConditionalsToFields({ + inputFields: urbanAddressFields, + newConditionals: [ + { + type: 'HIDE', + conditional: field(`${prefix}.urbanOrRural`).isUndefinedOrInArray([ + 'RURAL' + ]) + } + ] + }), + { + id: `${prefix}.village`, + type: 'TEXT', + required: false, + label: { + defaultMessage: 'Village', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.address.village.label` + }, + conditionals: [ + { + type: 'HIDE', + conditional: field(`${prefix}.urbanOrRural`).isUndefinedOrInArray([ + 'URBAN' + ]) + } + ] + } + ] return [ { diff --git a/src/form/v2/person/index.ts b/src/form/v2/person/index.ts index 3855578f3..8a7205260 100644 --- a/src/form/v2/person/index.ts +++ b/src/form/v2/person/index.ts @@ -12,7 +12,16 @@ import { FieldConfig, TranslationConfig } from '@opencrvs/toolkit/events' import { field } from '@opencrvs/toolkit/conditionals' import { getAddressFields } from './address' -import { createSelectOptions } from '../utils' +import { appendConditionalsToFields, createSelectOptions } from '../utils' + +export const PersonType = { + father: 'father', + mother: 'mother', + informant: 'informant', + applicant: 'applicant' +} as const + +export type PersonType = keyof typeof PersonType const IDTypes = { NATIONAL_ID: 'NATIONAL_ID', @@ -127,7 +136,30 @@ const educationalAttainmentOptions = createSelectOptions( educationalAttainmentMessageDescriptors ) -const getIdFields = (person: string): FieldConfig[] => [ +const YesNoTypes = { + YES: 'YES', + NO: 'NO' +} as const + +const yesNoMessageDescriptors = { + YES: { + defaultMessage: 'Yes', + id: 'form.field.label.Yes', + description: 'Label for form field radio option Yes' + }, + NO: { + defaultMessage: 'No', + id: 'form.field.label.No', + description: 'Label for form field radio option No' + } +} satisfies Record + +const yesNoRadioOptions = createSelectOptions( + YesNoTypes, + yesNoMessageDescriptors +) + +const getIdFields = (person: PersonType): FieldConfig[] => [ { id: `${person}.idType`, type: 'SELECT', @@ -195,7 +227,9 @@ const getIdFields = (person: string): FieldConfig[] => [ } ] -export const getInformantFields = (person: string): FieldConfig[] => [ +export const getPersonInputCommonFields = ( + person: PersonType +): FieldConfig[] => [ { id: `${person}.firstname`, type: 'TEXT', @@ -290,42 +324,91 @@ export const getInformantFields = (person: string): FieldConfig[] => [ id: `event.birth.action.declare.form.section.${person}.field.addressHelper.label` }, options: { fontVariant: 'h2' } - }, - ...getAddressFields(person) + } ] -export const getPersonInputFields = (person: string): FieldConfig[] => [ - ...getInformantFields(person), - { - id: `${person}.maritalStatus`, - type: 'SELECT', - required: false, - label: { - defaultMessage: 'Marital Status', - description: 'This is the label for the field', - id: `event.birth.action.declare.form.section.${person}.field.maritalStatus.label` +const fatherAddressFields = [ + ...appendConditionalsToFields({ + inputFields: [ + { + id: `${PersonType.father}.addressSameAsHelper`, + type: 'PARAGRAPH', + label: { + defaultMessage: "Same as mother's usual place of residence?", + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${PersonType.father}.field.addressSameAsHelper.label` + }, + options: { fontVariant: 'reg16' } + }, + { + id: `${PersonType.father}.addressSameAs`, + type: 'RADIO_GROUP', + options: yesNoRadioOptions, + required: true, + label: { + defaultMessage: "Same as mother's usual place of residence?", + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${PersonType.father}.field.address.addressSameAs.label` + } + } + ], + newConditionals: [ + { + type: 'HIDE', + conditional: field( + `${PersonType.mother}.detailsNotAvailable` + ).isInArray(['true']) + } + ] + }), + ...appendConditionalsToFields({ + inputFields: getAddressFields(PersonType.father), + newConditionals: [ + { + type: 'HIDE', + conditional: field(`${PersonType.father}.addressSameAs`).isInArray([ + YesNoTypes.YES + ]) + } + ] + }) +] +export const getPersonInputFields = (person: PersonType): FieldConfig[] => { + const isFather = person === PersonType.father + return [ + ...getPersonInputCommonFields(person), + ...(isFather ? fatherAddressFields : getAddressFields(person)), + { + id: `${person}.maritalStatus`, + type: 'SELECT', + required: false, + label: { + defaultMessage: 'Marital Status', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.maritalStatus.label` + }, + options: maritalStatusOptions }, - options: maritalStatusOptions - }, - { - id: `${person}.educationalAttainment`, - type: 'SELECT', - required: false, - label: { - defaultMessage: 'Level of education', - description: 'This is the label for the field', - id: `event.birth.action.declare.form.section.${person}.field.educationalAttainment.label` + { + id: `${person}.educationalAttainment`, + type: 'SELECT', + required: false, + label: { + defaultMessage: 'Level of education', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.educationalAttainment.label` + }, + options: educationalAttainmentOptions }, - options: educationalAttainmentOptions - }, - { - id: `${person}.occupation`, - type: 'TEXT', - required: false, - label: { - defaultMessage: 'Occupation', - description: 'This is the label for the field', - id: `event.birth.action.declare.form.section.${person}.field.occupation.label` + { + id: `${person}.occupation`, + type: 'TEXT', + required: false, + label: { + defaultMessage: 'Occupation', + description: 'This is the label for the field', + id: `event.birth.action.declare.form.section.${person}.field.occupation.label` + } } - } -] + ] +}