Skip to content

Commit

Permalink
feat: Add constants.humanName to allow countries to have custom full …
Browse files Browse the repository at this point in the history
…name format (#7812)

* Add humanName to constants.ts

To allow countries to have custom ordering for full names

#6830

* Use constants.humanName on the UserList.tsx comp

To ensure that we get the format from the country-config

#6830

* Create a utility function getLocalisedname()

To make the name more usable we had to extract the name formatting logic into it's own function.

#6830

* Use getLocalisedName on the UserList component

#6830

* Use getLocalisedName on the UserAudit comp

Replace older logic to get the name which was based on an assumption that we support names in multiple languages

#6830

* refactor: use getLocalisedName() @ InProgress.tsx

We've found cleaner way to make the rendered name customizable for each country through client copy from country-config

#6830

* Refactor the work queues to use getLocalisedName()

We need to update all the places where a citizen's name is being referenced to show it in the format that the country chooses

#6830

* Record changes in the CHANGELOG for this PR

#6830
  • Loading branch information
Siyasanga authored Nov 11, 2024
1 parent 99534e5 commit 9d98010
Show file tree
Hide file tree
Showing 15 changed files with 177 additions and 125 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
- Record audit action buttons are moved into action menu [#7390](https://github.com/opencrvs/opencrvs-core/issues/7390)
- Reoder the sytem user add/edit field for surname to be first, also change labels from `Last name` to `User's surname` and lastly remove the NID question from the form [#6830](https://github.com/opencrvs/opencrvs-core/issues/6830)
- Auth now allows exchanging user's token for a new record-specific token [#7728](https://github.com/opencrvs/opencrvs-core/issues/7728)
- Allow countries to customise the format of the full name in the sytem for `sytem users` and `citizens` e.g `{LastName} {MiddleName} {Firstname}`, in any case where one of the name is not provided e.g no `MiddleName`, we'll simply render e.g `{LastName} {FirstName}` without any extra spaces if that's the order set in `country-config`. [#6830](https://github.com/opencrvs/opencrvs-core/issues/6830)

## Bug fixes

Expand Down
6 changes: 6 additions & 0 deletions packages/client/src/i18n/messages/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ interface IConstantsMessages
refresh: MessageDescriptor
duplicateOf: MessageDescriptor
matchedTo: MessageDescriptor
humanName: MessageDescriptor
}
const messagesToDefine: IConstantsMessages = {
action: {
Expand Down Expand Up @@ -978,6 +979,11 @@ const messagesToDefine: IConstantsMessages = {
defaultMessage: `{registrationTargetDays} days - 1 year`,
description: `Label for registrations within {registrationTargetDays} days to 1 year`,
id: 'constants.withinTargetDaysTo1Year'
},
humanName: {
defaultMessage: `{lastName} {middleName} {firstName}`,
description: 'A localized order of the full name',
id: 'constants.humanName'
}
}
export const constantsMessages: Record<
Expand Down
16 changes: 16 additions & 0 deletions packages/client/src/utils/data-formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import { getDefaultLanguage } from '@client/i18n/utils'
import type { GQLComment } from '@client/utils/gateway-deprecated-do-not-use'
import { HumanName } from './gateway'
import { constantsMessages } from '@client/i18n/messages'
import { IntlShape } from 'react-intl'

interface INamesMap {
[key: string]: string
Expand Down Expand Up @@ -81,3 +83,17 @@ export const mergeArraysRemovingEmptyStrings = (
export function getPercentage(total: number, current: number) {
return current === 0 || total === 0 ? 0 : (current / total) * 100
}

export function getLocalisedName(
intl: IntlShape,
nameObject: HumanName
): string {
return intl
.formatMessage(constantsMessages.humanName, {
firstName: nameObject.firstNames,
middleName: nameObject.middleName,
lastName: nameObject.familyName
})
.replace(/\s+/g, ' ') // Remove extra spaces
.trim()
}
87 changes: 55 additions & 32 deletions packages/client/src/utils/draftUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,49 @@ import type {
GQLBirthEventSearchSet,
GQLDeathEventSearchSet
} from '@client/utils/gateway-deprecated-do-not-use'
import { createIntl, createIntlCache } from 'react-intl'

const cache = createIntlCache()
const intlEngish = createIntl(
{
locale: 'en',
messages: {}
},
cache
)
const intlBangla = createIntl(
{
locale: 'en',
messages: {}
},
cache
)

describe('draftUtils tests', () => {
describe('getDraftInformantFullName()', () => {
describe('Birth event', () => {
it('Returns child english name properly', () => {
expect(
getDeclarationFullName({
id: '7b57d8f9-4d2d-4f12-8d0a-b042fe14f3d4',
data: {
child: {
firstNames: 'মুশ্রাফুল',
familyName: 'হক',
firstNamesEng: 'Mushraful',
familyNameEng: 'Hoque'
}
getDeclarationFullName(
{
id: '7b57d8f9-4d2d-4f12-8d0a-b042fe14f3d4',
data: {
child: {
firstNames: 'মুশ্রাফুল',
familyName: 'হক',
firstNamesEng: 'Mushraful',
familyNameEng: 'Hoque'
}
},
event: Event.Birth,
savedOn: 1558037863335,
modifiedOn: 1558037867987
},
event: Event.Birth,
savedOn: 1558037863335,
modifiedOn: 1558037867987
})
).toBe('Mushraful Hoque')
intlEngish
)
).toBe('Hoque Mushraful')
})
it('Returns child bangla name properly', () => {
it('Returns child English name properly even though localed is Bangla', () => {
expect(
getDeclarationFullName(
{
Expand All @@ -55,30 +75,33 @@ describe('draftUtils tests', () => {
savedOn: 1558037863335,
modifiedOn: 1558037867987
},
'bn'
intlBangla
)
).toBe('হক')
).toBe('Hoque Mushraful')
})
})
describe('Death event', () => {
it('Returns deceased english name properly', () => {
expect(
getDeclarationFullName({
id: '7b57d8f9-4d2d-4f12-8d0a-b042fe14f3d4',
data: {
deceased: {
firstNames: 'মুশ্রাফুল',
familyName: 'হক',
familyNameEng: 'Hoque'
}
getDeclarationFullName(
{
id: '7b57d8f9-4d2d-4f12-8d0a-b042fe14f3d4',
data: {
deceased: {
firstNames: 'মুশ্রাফুল',
familyName: 'হক',
familyNameEng: 'Hoque'
}
},
event: Event.Death,
savedOn: 1558037863335,
modifiedOn: 1558037867987
},
event: Event.Death,
savedOn: 1558037863335,
modifiedOn: 1558037867987
})
intlBangla
)
).toBe('Hoque')
})
it('Returns child bangla name properly', () => {
it('Returns child English name properly even when the current locale is Bangla', () => {
expect(
getDeclarationFullName(
{
Expand All @@ -95,9 +118,9 @@ describe('draftUtils tests', () => {
savedOn: 1558037863335,
modifiedOn: 1558037867987
},
'bn'
intlEngish
)
).toBe('মুশ্রাফুল হক')
).toBe('Hoque Mushraful')
})
})
})
Expand Down
82 changes: 31 additions & 51 deletions packages/client/src/utils/draftUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
SUBMISSION_STATUS,
IPrintableDeclaration
} from '@client/declarations'
import { IFormSectionData } from '@client/forms'
import { Event, History, RegStatus } from '@client/utils/gateway'
import type {
GQLBirthEventSearchSet,
Expand All @@ -24,67 +23,48 @@ import type {
import { getEvent } from '@client/views/PrintCertificate/utils'
import { includes } from 'lodash'
import { EMPTY_STRING } from '@client/utils/constants'

const getEngName = (
sectionData: IFormSectionData,
lastNameFirst: boolean
): string => {
if (lastNameFirst) {
return `${sectionData.familyNameEng ?? ''} ${
sectionData.firstNamesEng ?? ''
}`
}
return [
sectionData.firstNamesEng,
sectionData.middleNameEng,
sectionData.familyNameEng
]
.filter(Boolean)
.join(' ')
.trim()
}

const getOtherName = (sectionData: IFormSectionData): string => {
return [
sectionData.firstNames,
sectionData.middleName,
sectionData.familyName
]
.filter(Boolean)
.join(' ')
.trim()
}

const getFullName = (
sectionData: IFormSectionData,
language = 'en',
lastNameFirst = false
): string => {
if (!sectionData) {
return EMPTY_STRING
}
if (language === 'en') {
return getEngName(sectionData, lastNameFirst)
}
return getOtherName(sectionData) || getEngName(sectionData, lastNameFirst)
}
import { getLocalisedName } from './data-formatting'
import { IntlShape } from 'react-intl'

/*
* lastNameFirst needs to be removed in #4464
*/
export const getDeclarationFullName = (
draft: IDeclaration,
language?: string,
lastNameFirst?: boolean
intl: IntlShape
) => {
switch (draft.event) {
case Event.Birth:
return getFullName(draft.data.child, language, lastNameFirst)
return draft.data.child
? getLocalisedName(intl, {
firstNames: draft.data.child.firstNamesEng as string,
middleName: draft.data.child.middleNameEng as string,
familyName: draft.data.child.familyNameEng as string
})
: EMPTY_STRING
case Event.Death:
return getFullName(draft.data.deceased, language, lastNameFirst)
return draft.data.deceased
? getLocalisedName(intl, {
firstNames: draft.data.deceased.firstNamesEng as string,
middleName: draft.data.deceased.middleNameEng as string,
familyName: draft.data.deceased.familyNameEng as string
})
: EMPTY_STRING
case Event.Marriage:
const brideName = getFullName(draft.data.bride, language, lastNameFirst)
const groomName = getFullName(draft.data.groom, language, lastNameFirst)
const brideName = draft.data.bride
? getLocalisedName(intl, {
firstNames: draft.data.bride.firstNamesEng as string,
middleName: draft.data.bride.middleNameEng as string,
familyName: draft.data.bride.familyNameEng as string
})
: EMPTY_STRING
const groomName = draft.data.groom
? getLocalisedName(intl, {
firstNames: draft.data.groom.firstNamesEng as string,
middleName: draft.data.groom.middleNameEng as string,
familyName: draft.data.groom.familyNameEng as string
})
: EMPTY_STRING
if (brideName && groomName) {
return `${groomName} & ${brideName}`
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,6 @@ class InProgressComponent extends React.Component<

transformDraftContent = () => {
const { intl } = this.props
const { locale } = intl
if (!this.props.drafts || this.props.drafts.length <= 0) {
return []
}
Expand All @@ -361,7 +360,7 @@ class InProgressComponent extends React.Component<
} else if (draft.event && draft.event.toString() === 'marriage') {
pageRoute = DRAFT_MARRIAGE_FORM_PAGE
}
const name = getDeclarationFullName(draft, locale)
const name = getDeclarationFullName(draft, intl)
const lastModificationDate = draft.modifiedOn || draft.savedOn
const actions: IAction[] = []

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ describe('In Progress tab', () => {
const EXPECTED_DATE_OF_REJECTION = formattedDuration(TIME_STAMP)

expect(data[0].id).toBe('e302f7c5-ad87-4117-91c1-35eaf2ea7be8')
expect(data[0].name).toBe('anik hoque')
expect(data[0].name).toBe('hoque anik')
expect(data[0].lastUpdated).toBe(EXPECTED_DATE_OF_REJECTION)
expect(data[0].event).toBe('Birth')
expect(data[0].actions).toBeDefined()
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/views/OfficeHome/outbox/Outbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export function Outbox() {

function transformDeclarationsReadyToSend() {
const items = declarations.map((declaration, index) => {
const name = getDeclarationFullName(declaration)
const name = getDeclarationFullName(declaration, intl)
let dateOfEvent
if (declaration.event && declaration.event.toString() === 'birth') {
dateOfEvent = declaration.data?.child?.childBirthDate as string
Expand Down
2 changes: 1 addition & 1 deletion packages/client/src/views/RecordAudit/RecordAudit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ describe('Record audit summary for WorkQueue declarations', () => {
component.find({ 'data-testid': 'type-value' }).hostNodes().text()
).toBe('Birth')
expect(component.find('#content-name').hostNodes().text()).toBe(
'Shakib Al Hasan'
'Al Hasan Shakib'
)
expect(
component
Expand Down
4 changes: 2 additions & 2 deletions packages/client/src/views/RecordAudit/RecordAudit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ const BodyContent = ({
assignment: data.fetchRegistration?.registration?.assignment
}
} else {
declaration = getGQLDeclaration(data.fetchRegistration, language)
declaration = getGQLDeclaration(data.fetchRegistration, intl)
}

return (
Expand Down Expand Up @@ -592,7 +592,7 @@ const BodyContent = ({
}
: getWQDeclarationData(
workqueueDeclaration as NonNullable<typeof workqueueDeclaration>,
language,
intl,
trackingId
)
const wqStatus = workqueueDeclaration?.registration
Expand Down
Loading

0 comments on commit 9d98010

Please sign in to comment.