import { IFormField , Ii18nFormField , ISelectOption , IConditionals , IFormSectionData , IConditional , SELECT_WITH_OPTIONS , RADIO_GROUP , CHECKBOX_GROUP , IRadioOption , ICheckboxOption , ISelectFormFieldWithDynamicOptions , INFORMATIVE_RADIO_GROUP , PARAGRAPH , IDynamicListFormField , IDynamicValueMapper , IFormData , IDynamicFormFieldValidators , IDynamicFormField , FETCH_BUTTON , ILoaderButton , IFieldInput , IFormSection , IQuery , DATE , IDateFormField , IFormSectionGroup , IRadioGroupFormField , RADIO_GROUP_WITH_NESTED_FIELDS , DOCUMENT_UPLOADER_WITH_OPTION } from '@client/forms' ; import { IntlShape , MessageDescriptor } from 'react-intl' ; import { getValidationErrorsForForm , IFieldErrors , Errors } from '@client/forms/validation' ; import { OFFLINE_LOCATIONS_KEY , OFFLINE_FACILITIES_KEY , ILocation , IOfflineData , LocationType } from '@client/offline/reducer' ; import { Validation , isAValidDateFormat , isDateNotInFuture } from '@client/utils/validate' ; import moment from 'moment' ; import { IRadioOption as CRadioOption } from '@opencrvs/components/lib/forms' ; import { IDynamicValues } from '@client/navigation' ; import { generateLocations } from '@client/utils/locationUtils' ; import { callingCountries } from 'country-data' ; interface IRange { start : number ; end ? : number ; value : string ; } export const internationaliseOptions = ( intl , options ) => { return options . map ( ( opt ) => { return { ... opt , label : intl . formatMessage ( opt . label ) } ; } ) ; } ; export const internationaliseFieldObject = ( intl , field ) : Ii18nFormField => { const base = { ... field , label : field . type === PARAGRAPH ? field . label : intl . formatMessage ( field . label ) , helperText : field . helperText && intl . formatMessage ( field . helperText ) , tooltip : field . tooltip && intl . formatMessage ( field . tooltip ) , description : field . description && intl . formatMessage ( field . description ) , placeholder : field . placeholder && intl . formatMessage ( field . placeholder ) } ; if ( base . type === SELECT_WITH_OPTIONS || base . type === INFORMATIVE_RADIO_GROUP || base . type === CHECKBOX_GROUP || base . type === DOCUMENT_UPLOADER_WITH_OPTION ) { ; ( base as any ) . options = internationaliseOptions ( intl , base . options ) ; } if ( base . type === RADIO_GROUP || base . type === RADIO_GROUP_WITH_NESTED_FIELDS ) { ; ( base as any ) . options = internationaliseOptions ( intl , base . options ) ; if ( ( field as IDateFormField ) . notice ) { ; ( base as any ) . notice = intl . formatMessage ( ( field as IRadioGroupFormField ) . notice ) ; } } if ( base . type === DATE && ( field as IDateFormField ) . notice ) { ; ( base as any ) . notice = intl . formatMessage ( ( field as IDateFormField ) . notice ) ; } if ( base . type === FETCH_BUTTON ) { ; ( base as any ) . modalTitle = intl . formatMessage ( ( field as ILoaderButton ) . modalTitle ) ; ( base as any ) . successTitle = intl . formatMessage ( ( field as ILoaderButton ) . successTitle ) ; ( base as any ) . errorTitle = intl . formatMessage ( ( field as ILoaderButton ) . errorTitle ) ; } return base as Ii18nFormField ; } ; export const generateOptions = ( options , optionType ) : ISelectOption [ ] => { const optionsArray = [ ] ; options . forEach ( ( option , index ) => { optionsArray . push ( { value : option . id , label : { id : `${ optionType }.${ option . id }` , defaultMessage : option . name , description : `${ optionType } select item for ${ option . id }` } } ) ; } ) ; return optionsArray ; } ; export const getFieldType = ( field , values ) : string => { if ( ! field . dynamicDefinitions . type ) { return field . type ; } switch ( field . dynamicDefinitions . type . kind ) { case 'dynamic' : return field . dynamicDefinitions . type . typeMapper ( values [ field . dynamicDefinitions . type . dependency ] as string ) ; case 'static' : default : return field . dynamicDefinitions . type . staticType ; } } ; export const getFieldLabel = ( field , values ) : MessageDescriptor | undefined => { if ( ! field . dynamicDefinitions . label ) { return undefined ; } return field . dynamicDefinitions . label . labelMapper ( values [ field . dynamicDefinitions . label . dependency ] as string ) ; } ; export const getFieldHelperText = ( field , values ) : MessageDescriptor | undefined => { if ( ! field . dynamicDefinitions . helperText ) { return undefined ; } return field . dynamicDefinitions . helperText . helperTextMapper ( values [ field . dynamicDefinitions . helperText . dependency ] as string ) ; } ; export const getFieldLabelToolTip = ( field , values ) : MessageDescriptor | undefined => { if ( ! field . dynamicDefinitions . tooltip ) { return undefined ; } return field . dynamicDefinitions . tooltip . tooltipMapper ( values [ field . dynamicDefinitions . tooltip . dependency ] as string ) ; } ; export const getFieldValidation = ( field , values ) : Validation [ ] => { const validate = [ ] ; if ( field . dynamicDefinitions && field . dynamicDefinitions . validate && field . dynamicDefinitions . validate . length > 0 ) { field . dynamicDefinitions . validate . map ( ( element ) => { const params = [ ] ; element . dependencies . map ( ( dependency ) => params . push ( values [ dependency ] ) ) ; const fun = element . validator ( ... params ) ; validate . push ( fun ) ; return element ; } ) ; } return validate ; } ; export const getVisibleGroupFields = ( group ) => { return group . fields . filter ( ( field ) => ! field . hidden ) ; } ; export const getFieldOptions = ( field , values , resources ) => { const locations = resources [ OFFLINE_LOCATIONS_KEY ] ; const dependencyVal = values [ field . dynamicOptions . dependency ] as string ; if ( field . dynamicOptions . jurisdictionType ) { return generateOptions ( Object . values ( locations ) . filter ( ( location ) => { return ( location . jurisdictionType === field . dynamicOptions . jurisdictionType ) ; } ) , 'location' ) ; } else if ( resources && field . dynamicOptions . resource === OFFLINE_LOCATIONS_KEY ) { if ( ! dependencyVal ) { return [ ] ; } let partOf ; if ( dependencyVal === window . config . COUNTRY . toUpperCase ( ) ) { partOf = 'Location/0' ; } else { partOf = `Location/${ dependencyVal }` ; } return generateOptions ( Object . values ( locations ) . filter ( ( location ) => { return location . partOf === partOf ; } ) , 'location' ) ; } else if ( resources && field . dynamicOptions . resource === OFFLINE_FACILITIES_KEY ) { const facilities = resources [ OFFLINE_FACILITIES_KEY ] ; return generateOptions ( Object . values ( facilities ) , 'facility' ) ; } else { let options ; if ( ! field . dynamicOptions . options ) { throw new Error ( `Dependency '${ dependencyVal }' has illegal value, the value should have an entry in the dynamic options object.` ) ; } else { options = field . dynamicOptions . options [ dependencyVal ] || [ ] ; } return options ; } } ; interface INested { [ key ] : any ; } const getNestedValue = ( obj , key ) => { return key . split ( '.' ) . reduce ( ( res , k ) => res [ k ] || '' , obj ) ; } ; const betweenRange = ( range , check ) => range . end ? check >= range . start && check <= range . end : check >= range . start ; export const getFieldOptionsByValueMapper = ( field , values , valueMapper ) => { const dependencyVal = getNestedValue ( values , field . dynamicItems . dependency ) as unknown as string ; const firstKey = Object . keys ( field . dynamicItems . items ) [ 0 ] ; if ( ! dependencyVal ) { return field . dynamicItems . items [ firstKey ] ; } const mappedValue = valueMapper ( dependencyVal ) ; let items ; if ( ! field . dynamicItems . items [ mappedValue ] ) { items = field . dynamicItems . items [ firstKey ] ; } else { items = field . dynamicItems . items [ mappedValue ] ; } return items ; } ; export const diffDoB = ( doB ) => { if ( ! isAValidDateFormat ( doB ) || ! isDateNotInFuture ( doB ) ) return 'within45days' ; const todaysDate = moment ( Date . now ( ) ) ; const birthDate = moment ( doB ) ; const diffInDays = todaysDate . diff ( birthDate , 'days' ) ; const ranges = [ { start : 0 , end : 45 , value : 'within45days' } , { start : 46 , end : 5 * 365 , value : 'between46daysTo5yrs' } , { start : 5 * 365 + 1 , value : 'after5yrs' } ] ; const valueWithinRange = ranges . find ( ( range ) => betweenRange ( range , diffInDays ) ) ; return valueWithinRange ? valueWithinRange . value : '' ; } ; export function isCityLocation ( locations , locationId ) { const selectedLocation = locations [ locationId ] ; if ( selectedLocation ) { if ( selectedLocation . jurisdictionType === 'CITYCORPORATION' ) { return true ; } else { return false ; } } else { return false ; } } export function isDefaultCountry ( countryCode ) { return countryCode === window . config . COUNTRY . toUpperCase ( ) ; } export function getListOfLocations ( resource , resourceType ) { return resource [ resourceType ] ; } interface IVars { [ key ] : any ; } export function getInputValues ( inputs , values ) { const variables = { } ; inputs . forEach ( ( input ) => { if ( input . type && input . type === 'ENVIRONMENT' ) { variables [ input . name ] = window . config [ input . valueField as keyof typeof window . config ] ; } else { variables [ input . name ] = values [ input . valueField ] ; } } ) ; return variables ; } export function getQueryData ( field , values ) { const selectedValue = values [ field . querySelectorInput . valueField ] as string ; const queryData = field . queryMap [ selectedValue ] ; if ( ! queryData ) { return ; } const variables = getInputValues ( queryData . inputs , values ) ; queryData . variables = variables ; return queryData ; } export const getConditionalActionsForField = ( field , values , resources ? , draftData ? ) : string [ ] => { if ( ! field . conditionals ) { return [ ] ; } return ( field . conditionals . filter ( ( conditional ) => eval ( conditional . expression ) ) . map ( ( conditional ) => conditional . action ) ) ; } ; export const getVisibleSectionGroupsBasedOnConditions = ( section , values , draftData ? ) : IFormSectionGroup [ ] => { return section . groups . filter ( ( group ) => { if ( ! group . conditionals ) { return true ; } return ( group . conditionals . filter ( ( conditional ) => eval ( conditional . expression ) ) . map ( ( conditional ) => conditional . action ) . includes ( 'hide' ) !== true ) ; } ) ; } ; export const getVisibleOptions = ( radioOptions , draftData ) : CRadioOption [ ] => { return radioOptions . filter ( ( option ) => { if ( ! option . conditionals ) { return true ; } return ( option . conditionals . filter ( ( conditional ) => eval ( conditional . expression ) ) . map ( ( conditional ) => conditional . action ) . includes ( 'hide' ) !== true ) ; } ) ; } ; export const getSectionFields = ( section , values ? , draftData ? ) => { let fields = [ ] ; getVisibleSectionGroupsBasedOnConditions ( section , values || { } , draftData ) . forEach ( ( group ) => ( fields = fields . concat ( group . fields ) ) ) ; return fields ; } ; export const hasFormError = ( fields , values , resource ? , drafts ? ) : boolean => { const errors = getValidationErrorsForForm ( fields , values , resource , drafts ) ; const fieldListWithErrors = Object . values ( errors ) . filter ( ( error ) => ( error as IFieldErrors ) . errors . length > 0 || Object . values ( error . nestedFields ) . some ( ( nestedFieldErrors ) => nestedFieldErrors . length > 0 ) ) ; return fieldListWithErrors && fieldListWithErrors . length > 0 ; } ; export const convertToMSISDN = ( phone ) => { const countryCode = callingCountries [ window . config . COUNTRY . toUpperCase ( ) ] . countryCallingCodes [ 0 ] ; if ( phone . startsWith ( countryCode ) || `+${ phone }` . startsWith ( countryCode ) ) { return phone . startsWith ( '+' ) ? phone : `+${ phone }` ; } return phone . startsWith ( '0' ) ? `${ countryCode }${ phone . substring ( 1 ) }` : `${ countryCode }${ phone }` ; } ; export const conditionals = { iDType : { action : 'hide' , expression : "!values.iDType || (values.iDType !== 'OTHER')" } , fathersDetailsExist : { action : 'hide' , expression : '!values.fathersDetailsExist' } , permanentAddressSameAsMother : { action : 'hide' , expression : 'values.permanentAddressSameAsMother' } , addressSameAsMother : { action : 'hide' , expression : 'values.addressSameAsMother' } , currentAddressSameAsPermanent : { action : 'hide' , expression : 'values.currentAddressSameAsPermanent' } , countryPermanent : { action : 'hide' , expression : '!values.countryPermanent' } , isDefaultCountryPermanent : { action : 'hide' , expression : 'isDefaultCountry(values.countryPermanent)' } , statePermanent : { action : 'hide' , expression : '!values.statePermanent' } , districtPermanent : { action : 'hide' , expression : '!values.districtPermanent' } , addressLine4Permanent : { action : 'hide' , expression : '!values.addressLine4Permanent' } , addressLine3Permanent : { action : 'hide' , expression : '!values.addressLine3Permanent' } , country : { action : 'hide' , expression : '!values.country' } , isDefaultCountry : { action : 'hide' , expression : 'isDefaultCountry(values.country)' } , state : { action : 'hide' , expression : '!values.state' } , district : { action : 'hide' , expression : '!values.district' } , addressLine4 : { action : 'hide' , expression : '!values.addressLine4' } , addressLine3 : { action : 'hide' , expression : '!values.addressLine3' } , uploadDocForWhom : { action : 'hide' , expression : '!values.uploadDocForWhom' } , motherCollectsCertificate : { action : 'hide' , expression : 'values.personCollectingCertificate!="MOTHER"' } , fatherCollectsCertificate : { action : 'hide' , expression : 'values.personCollectingCertificate!="FATHER"' } , informantCollectsCertificate : { action : 'hide' , expression : 'values.personCollectingCertificate!="INFORMANT"' } , otherPersonCollectsCertificate : { action : 'hide' , expression : 'values.personCollectingCertificate!="OTHER"' } , birthCertificateCollectorNotVerified : { action : 'hide' , expression : '!(values.personCollectingCertificate=="MOTHER" && values.motherDetails===false) && !(values.personCollectingCertificate=="FATHER" && values.fatherDetails===false) && !(values.personCollectingCertificate =="OTHER" && values.otherPersonSignedAffidavit===false)' } , deathCertificateCollectorNotVerified : { action : 'hide' , expression : '!(values.personCollectingCertificate=="INFORMANT" && values.informantDetails===false) && !(values.personCollectingCertificate =="OTHER" && values.otherPersonSignedAffidavit===false)' } , placeOfBirthHospital : { action : 'hide' , expression : '(values.placeOfBirth!="HOSPITAL" && values.placeOfBirth!="OTHER_HEALTH_INSTITUTION")' } , deathPlaceAddressTypeHeathInstitue : { action : 'hide' , expression : 'values.deathPlaceAddress!="HEALTH_FACILITY"' } , otherBirthEventLocation : { action : 'hide' , expression : '(values.placeOfBirth!="OTHER" && values.placeOfBirth!="PRIVATE_HOME")' } , isNotCityLocation : { action : 'hide' , expression : '(resources && resources.locations && isCityLocation(resources.locations,values.addressLine4))' } , isCityLocation : { action : 'hide' , expression : '!(resources && resources.locations && isCityLocation(resources.locations,values.addressLine4))' } , isNotCityLocationPermanent : { action : 'hide' , expression : '(resources && resources.locations && isCityLocation(resources.locations,values.addressLine4Permanent))' } , isCityLocationPermanent : { action : 'hide' , expression : '!(resources && resources.locations && isCityLocation(resources.locations,values.addressLine4Permanent))' } , iDAvailable : { action : 'hide' , expression : '!values.iDType || values.iDType === "NO_ID"' } , applicantPermanentAddressSameAsCurrent : { action : 'hide' , expression : 'values.applicantPermanentAddressSameAsCurrent' } , deathPlaceOther : { action : 'hide' , expression : 'values.deathPlaceAddress !== "OTHER"' } , deathPlaceAtPrivateHome : { action : 'hide' , expression : 'values.deathPlaceAddress !== "PRIVATE_HOME"' } , deathPlaceAtOtherLocation : { action : 'hide' , expression : 'values.deathPlaceAddress !== "OTHER"' } , causeOfDeathEstablished : { action : 'hide' , expression : '!values.causeOfDeathEstablished' } , isMarried : { action : 'hide' , expression : '(!values.maritalStatus || values.maritalStatus !== "MARRIED")' } , identifierIDSelected : { action : 'hide' , expression : '(!values.iDType || (values.iDType !== "BIRTH_REGISTRATION_NUMBER" && values.iDType !== "NATIONAL_ID"))' } , otherRelationship : { action : 'hide' , expression : 'values.applicantsRelationToDeceased !== "OTHER"' } , fatherContactDetailsRequired : { action : 'hide' , expression : '(draftData && draftData.registration && draftData.registration.whoseContactDetails === "FATHER")' } , withIn45Days : { action : 'hide' , expression : '(draftData && draftData.child && draftData.child.childBirthDate && diffDoB(draftData.child.childBirthDate) === "within45days") || !draftData.child || !draftData.child.childBirthDate' } , between46daysTo5yrs : { action : 'hide' , expression : '(draftData && draftData.child && draftData.child.childBirthDate && diffDoB(draftData.child.childBirthDate) === "between46daysTo5yrs") || !draftData.child || !draftData.child.childBirthDate' } , after5yrs : { action : 'hide' , expression : '(draftData && draftData.child && draftData.child.childBirthDate && diffDoB(draftData.child.childBirthDate) === "after5yrs")  || !draftData.child || !draftData.child.childBirthDate' } , deceasedNationIdSelected : { action : 'hide' , expression : '(values.uploadDocForDeceased && !!values.uploadDocForDeceased.find(a => ["National ID (front)", "National ID (Back)"].indexOf(a.optionValues[1]) > -1))' } , isRegistrarRoleSelected : { action : 'hide' , expression : 'values.role!=="LOCAL_REGISTRAR"' } , certCollectorOther : { action : 'hide' , expression : 'values.type !== "OTHER"' } , userAuditReasonSpecified : { action : 'hide' , expression : 'values.reason === "OTHER"' } , userAuditReasonOther : { action : 'hide' , expression : 'values.reason !== "OTHER"' } , isAuditActionDeactivate : { action : 'hide' , expression : 'draftData.formValues.action !== "DEACTIVATE"' } , isAuditActionReactivate : { action : 'hide' , expression : 'draftData.formValues.action !== "REACTIVATE"' } } ;