Skip to content

Commit

Permalink
Merge branch 'develop' into feat/ocrvs-7978/qr-reader
Browse files Browse the repository at this point in the history
  • Loading branch information
tahmidrahman-dsi authored Jan 16, 2025
2 parents f2368f5 + c11de6e commit d6ea209
Show file tree
Hide file tree
Showing 102 changed files with 2,787 additions and 552 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
- Fix the informant column on the Perfomance page showing "Other family member" when `Someone else` is selected for a registration [#6157](https://github.com/opencrvs/opencrvs-core/issues/6157)
- Fix the event name displayed in email templates for death correction requests [#7703](https://github.com/opencrvs/opencrvs-core/issues/7703)

## 1.6.3 Release candidate

### Improvements

- For countries where local phone numbers start with 0, we now ensure the prefix remains unchanged when converting to and from the international format.

## 1.6.2 Release candidate

### Bug fixes
Expand Down
10 changes: 5 additions & 5 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,12 @@ services:
depends_on:
- base
environment:
- MONGO_URL=mongodb://mongo1/events
- ES_HOST=elasticsearch:9200
- COUNTRY_CONFIG_URL=http://countryconfig:3040/
- EVENTS_MONGO_URL=mongodb://mongo1/events
- USER_MGNT_MONGO_URL=mongodb://mongo1/user-mgnt
- ES_URL=http://elasticsearch:9200
- COUNTRY_CONFIG_URL=http://countryconfig:3040
- DOCUMENTS_URL=http://documents:9050
- USER_MANAGEMENT_URL=http://localhost:3030/

- USER_MANAGEMENT_URL=http://user-mgnt:3030
# User facing services
workflow:
image: opencrvs/ocrvs-workflow:${VERSION}
Expand Down
2 changes: 1 addition & 1 deletion packages/auth/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"sourceMap": true,
"moduleResolution": "node",
"rootDir": ".",
"lib": ["esnext.asynciterable", "es6", "es2017"],
"lib": ["esnext.asynciterable", "es6", "es2019"],
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,10 @@ describe('phone number conversion from international format back to local format
expect(convertToLocal('+260211000000', 'ZMB')).toBe('0211000000')
expect(convertToLocal('+358504700715', 'FIN')).toBe('0504700715')
expect(convertToLocal('+237666666666', 'CMR')).toBe('666666666')
expect(convertToLocal('+8801700000000', 'BGD')).toBe('01700000000')
expect(convertToLocal('+260211000000')).toBe('0211000000')
expect(convertToLocal('+358504700715')).toBe('0504700715')
expect(convertToLocal('+237666666666')).toBe('666666666')
expect(convertToLocal('+8801700000000')).toBe('01700000000')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -97,28 +97,36 @@ export const certificateDateTransformer =

export const convertToLocal = (
mobileWithCountryCode: string,
alpha3CountryCode: string
alpha3CountryCode?: string
) => {
/*
* If country is the fictional demo country (Farajaland), use Zambian number format
*/

const countryCode = countryAlpha3toAlpha2(alpha3CountryCode)
const phoneUtil = PhoneNumberUtil.getInstance()
const number = phoneUtil.parse(mobileWithCountryCode)
const countryCode = alpha3CountryCode
? countryAlpha3toAlpha2(alpha3CountryCode)
: phoneUtil.getRegionCodeForNumber(number)

if (!countryCode) {
return
}

const phoneUtil = PhoneNumberUtil.getInstance()

if (!phoneUtil.isPossibleNumberString(mobileWithCountryCode, countryCode)) {
return
}
const number = phoneUtil.parse(mobileWithCountryCode, countryCode)

return phoneUtil
let nationalFormat = phoneUtil
.format(number, PhoneNumberFormat.NATIONAL)
.replace(/[^A-Z0-9]+/gi, '')

// This is a special case for countries that have a national prefix of 0
if (
phoneUtil.getNddPrefixForRegion(countryCode, true) === '0' &&
!nationalFormat.startsWith('0')
) {
nationalFormat = '0' + nationalFormat
}
return nationalFormat
}

export const localPhoneTransformer =
Expand All @@ -131,7 +139,9 @@ export const localPhoneTransformer =
) => {
const fieldName = transformedFieldName || field.name
const msisdnPhone = get(queryData, fieldName as string) as unknown as string

if (!msisdnPhone) {
return transformedData
}
const localPhone = convertToLocal(msisdnPhone, window.config.COUNTRY)

transformedData[sectionId][field.name] = localPhone
Expand Down
7 changes: 7 additions & 0 deletions packages/client/src/offline/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
*/
import { IOfflineDataState, IOfflineData } from '@client/offline/reducer'
import { IStoreState } from '@client/store'
import { createSelector } from '@reduxjs/toolkit'
import { merge } from 'lodash'

const getOfflineState = (store: IStoreState): IOfflineDataState => store.offline
Expand Down Expand Up @@ -46,6 +47,12 @@ export const getOfflineData = (store: IStoreState): IOfflineData => {
return data
}

export const getLocations = createSelector(getOfflineData, (data) => ({
...data.locations,
...data.facilities,
...data.offices
}))

export const selectCountryBackground = (store: IStoreState) => {
const countryBackground = getKey(store, 'offlineData').config
?.LOGIN_BACKGROUND
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

/* eslint-disable */
import { InputField } from '@client/components/form/InputField'
import { DATE, PARAGRAPH, TEXT } from '@client/forms'
import { DATE, IFormFieldValue, PARAGRAPH, TEXT } from '@client/forms'
import { DateField } from '@opencrvs/components/lib/DateField'
import { Text } from '@opencrvs/components/lib/Text'
import { TextInput } from '@opencrvs/components/lib/TextInput'
Expand All @@ -27,11 +27,10 @@ import {
} from './utils'
import { Errors, getValidationErrorsForForm } from './validation'

import { ActionFormData } from '@opencrvs/commons'
import {
ActionFormData,
FieldConfig,
FieldValue,
FieldValueByType,
FileFieldValue
} from '@opencrvs/commons/client'
import {
Expand All @@ -50,6 +49,14 @@ import {
} from 'react-intl'
import { FileInput } from './inputs/FileInput/FileInput'

import { BulletList } from '@client/v2-events/features/events/registered-fields/BulletList'
import { Checkbox } from '@client/v2-events/features/events/registered-fields/Checkbox'
import { Select } from '@client/v2-events/features/events/registered-fields/Select'
import { countries } from '@client/utils/countries'
import { SelectOption } from '@opencrvs/commons'
import { SelectCountry } from '@client/v2-events/features/events/registered-fields/SelectCountry'
import { formatISO } from 'date-fns'

const fadeIn = keyframes`
from { opacity: 0; }
to { opacity: 1; }
Expand All @@ -72,7 +79,7 @@ interface GeneratedInputFieldProps<FieldType extends FieldConfig> {
onChange: (e: React.ChangeEvent) => void
onBlur: (e: React.FocusEvent) => void
resetDependentSelectValues: (name: string) => void
value: FieldValueByType[FieldType['type']]
value: IFormFieldValue
touched: boolean
error: string
formData: ActionFormData
Expand Down Expand Up @@ -175,7 +182,7 @@ const GeneratedInputField = React.memo(
return (
<InputField {...inputFieldProps}>
<TextInput
type="text"
type={fieldDefinition.options?.type ?? 'text'}
{...inputProps}
isDisabled={disabled}
maxLength={fieldDefinition.options?.maxLength}
Expand All @@ -196,6 +203,36 @@ const GeneratedInputField = React.memo(
</InputField>
)
}
if (fieldDefinition.type === 'BULLET_LIST') {
return <BulletList {...fieldDefinition} />
}
if (fieldDefinition.type === 'SELECT') {
return (
<Select
{...fieldDefinition}
value={inputProps.value as string}
onChange={(val: string) => setFieldValue(fieldDefinition.id, val)}
/>
)
}
if (fieldDefinition.type === 'COUNTRY') {
return (
<SelectCountry
{...fieldDefinition}
value={inputProps.value as string}
setFieldValue={setFieldValue}
/>
)
}
if (fieldDefinition.type === 'CHECKBOX') {
return (
<Checkbox
{...fieldDefinition}
value={value as string}
setFieldValue={setFieldValue}
/>
)
}
return <div>Unsupported field type {fieldDefinition.type}</div>
}
)
Expand Down Expand Up @@ -365,10 +402,13 @@ class FormSectionComponent extends React.Component<AllProps> {

const conditionalActions: string[] = getConditionalActionsForField(
field,
{ $form: values, $now: new Date().toISOString().split('T')[0] }
{
$form: makeFormikFieldIdsOpenCRVSCompatible(values),
$now: formatISO(new Date(), { representation: 'date' })
}
)

if (conditionalActions.includes('hide')) {
if (conditionalActions.includes('HIDE')) {
return null
}

Expand Down
6 changes: 5 additions & 1 deletion packages/client/src/v2-events/components/forms/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ const initialValueMapping: Record<FieldType, FieldValue | null> = {
[FieldType.RADIO_GROUP]: INITIAL_RADIO_GROUP_VALUE,
[FieldType.PARAGRAPH]: INITIAL_PARAGRAPH_VALUE,
[FieldType.FILE]: null,
[FieldType.HIDDEN]: null
[FieldType.HIDDEN]: null,
[FieldType.BULLET_LIST]: null,
[FieldType.CHECKBOX]: null,
[FieldType.COUNTRY]: null,
[FieldType.SELECT]: null
}

export function getInitialValues(fields: FieldConfig[]) {
Expand Down
9 changes: 5 additions & 4 deletions packages/client/src/v2-events/components/forms/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { MessageDescriptor } from 'react-intl'
import { formatISO } from 'date-fns'
import {
ConditionalParameters,
FieldConfig,
Expand All @@ -27,7 +28,7 @@ export interface Errors {
}

function isFieldHidden(field: FieldConfig, params: ConditionalParameters) {
const hasShowRule = field.conditionals.some(
const hasShowRule = (field.conditionals ?? []).some(
(conditional) => conditional.type === 'SHOW'
)
const validConditionals = getConditionalActionsForField(field, params)
Expand All @@ -36,7 +37,7 @@ function isFieldHidden(field: FieldConfig, params: ConditionalParameters) {
}

function isFieldDisabled(field: FieldConfig, params: ConditionalParameters) {
const hasEnableRule = field.conditionals.some(
const hasEnableRule = (field.conditionals ?? []).some(
(conditional) => conditional.type === 'ENABLE'
)
const validConditionals = getConditionalActionsForField(field, params)
Expand All @@ -52,7 +53,7 @@ function getValidationErrors(
) {
const conditionalParameters = {
$form: values,
$now: new Date().toISOString().split('T')[0]
$now: formatISO(new Date(), { representation: 'date' })
}

if (
Expand Down Expand Up @@ -80,7 +81,7 @@ function getValidationErrors(
.filter((validation) => {
return !validate(validation.validator, {
$form: values,
$now: new Date().toISOString().split('T')[0]
$now: formatISO(new Date(), { representation: 'date' })
})
})
.map((validation) => ({ message: validation.message }))
Expand Down
29 changes: 29 additions & 0 deletions packages/client/src/v2-events/components/withSuspense.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*
* OpenCRVS is also distributed under the terms of the Civil Registration
* & Healthcare Disclaimer located at http://opencrvs.org/license.
*
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/

import React from 'react'
import { Spinner } from '@opencrvs/components'

/**
* HOC to wrap a component in a suspense boundary with a spinner fallback.
*/
export function withSuspense<
ComponentProps extends React.JSX.IntrinsicAttributes
>(Component: React.ComponentType<ComponentProps>) {
// eslint-disable-next-line react/display-name
return (props: ComponentProps) => (
<React.Suspense
fallback={<Spinner id={`page-spinner-${new Date().getTime()}`} />}
>
<Component {...props} />
</React.Suspense>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ function EventSelector() {
{eventConfigurations.map((event) => (
<RadioButton
key={`${event.id}event`}
id="select_birth_event"
id={`select_${event.id}_event`}
label={intl.formatMessage(event.label)}
name={`${event.id}event`}
selected={eventType === event.id ? event.id : ''}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ export function ValidateEvent() {
const validateEvent = events.actions.validate

useEffect(() => {
validateEvent.mutate({ eventId, data: {}, transactionId: uuid() })
validateEvent.mutate({
eventId,
data: {},
transactionId: uuid(),
duplicates: []
})
navigate(ROUTES.V2.path)
}, [validateEvent, eventId, navigate])

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import React from 'react'
import { defineMessages, MessageDescriptor, useIntl } from 'react-intl'
import styled from 'styled-components'

import { formatISO } from 'date-fns'
import {
ActionFormData,
FieldConfig,
Expand All @@ -31,6 +32,7 @@ import {

import { EventConfig } from '@opencrvs/commons'
import { FileOutput } from '@client/v2-events/components/forms/inputs/FileInput/FileInput'
import { getConditionalActionsForField } from '@client/v2-events/components/forms/utils'

const Row = styled.div<{
position?: 'left' | 'center'
Expand Down Expand Up @@ -252,6 +254,16 @@ function ReviewComponent({
// this means a value display row in not rendered at all
FIELD_TYPE_FORMATTERS[field.type] !== null
)
.filter(
(field) =>
// Omit hidden fields
!getConditionalActionsForField(field, {
$form: form,
$now: formatISO(new Date(), {
representation: 'date'
})
}).includes('HIDE')
)
.map((field) => {
const Output =
FIELD_TYPE_FORMATTERS[field.type] || DefaultOutput
Expand Down
Loading

0 comments on commit d6ea209

Please sign in to comment.