From a533093b4d3bc697e6a1b55675482fe371aa5297 Mon Sep 17 00:00:00 2001
From: "Md. Ashikul Alam" <32668488+Nil20@users.noreply.github.com>
Date: Thu, 9 Jan 2025 16:53:26 +0600
Subject: [PATCH] (User roles) fix search scope bugs (#8267)
* fix: amend active tab id of advance search
* fix: hide advance searching based on scopes
* fix: remove marriage scope from advance search component permission scope
* chore: refactor advance search section to receive param
* chore: refactor advance search section creator with user office id
* chore: add filter location function
* fix: add comment for additional props
* fix: refactor variable name
* fix: amend accordion state function with office id
* fix: update advance search test with user details
---
packages/client/src/App.tsx | 4 +-
.../client/src/components/Header/Header.tsx | 13 +-
.../components/form/FormFieldGenerator.tsx | 3 +-
.../advancedSearch/fieldDefinitions/Birth.ts | 23 +++-
.../advancedSearch/fieldDefinitions/Death.ts | 23 +++-
packages/client/src/forms/index.ts | 2 +
packages/client/src/hooks/useAuthorization.ts | 20 ++-
.../client/src/search/advancedSearch/utils.ts | 49 ++++---
.../client/src/utils/locationUtils.test.ts | 8 +-
packages/client/src/utils/locationUtils.ts | 86 ++++++++----
.../SearchResult/AdvancedSearch.test.tsx | 9 +-
.../src/views/SearchResult/AdvancedSearch.tsx | 122 ++++++++++++++----
12 files changed, 267 insertions(+), 95 deletions(-)
diff --git a/packages/client/src/App.tsx b/packages/client/src/App.tsx
index 5f87ca8110b..e2d7c4b6ba0 100644
--- a/packages/client/src/App.tsx
+++ b/packages/client/src/App.tsx
@@ -160,9 +160,7 @@ export const routesConfig = [
SCOPES.SEARCH_BIRTH,
SCOPES.SEARCH_BIRTH_MY_JURISDICTION,
SCOPES.SEARCH_DEATH,
- SCOPES.SEARCH_DEATH_MY_JURISDICTION,
- SCOPES.SEARCH_MARRIAGE,
- SCOPES.SEARCH_MARRIAGE_MY_JURISDICTION
+ SCOPES.SEARCH_DEATH_MY_JURISDICTION
]}
>
diff --git a/packages/client/src/components/Header/Header.tsx b/packages/client/src/components/Header/Header.tsx
index c05e77f25ab..eedd185700c 100644
--- a/packages/client/src/components/Header/Header.tsx
+++ b/packages/client/src/components/Header/Header.tsx
@@ -126,7 +126,14 @@ const HeaderComponent = (props: IFullProps) => {
changeTeamLocation
} = props
- const { canCreateUser, canSearchRecords } = usePermissions()
+ const {
+ canCreateUser,
+ canSearchRecords,
+ canSearchBirthRecords,
+ canSearchDeathRecords
+ } = usePermissions()
+
+ const canDoAdvanceSearch = canSearchBirthRecords || canSearchDeathRecords
const getMobileHeaderActionProps = (activeMenuItem: ACTIVE_MENU_ITEM) => {
const locationId = parse(router.location.search).locationId as string
@@ -303,7 +310,7 @@ const HeaderComponent = (props: IFullProps) => {
})
}
- const navigationList: INavigationType[] = [
+ const advancedSearchNavigationList: INavigationType[] = [
{
label: intl.formatMessage(messages.advancedSearch),
id: ADVANCED_SEARCH_TEXT,
@@ -324,7 +331,7 @@ const HeaderComponent = (props: IFullProps) => {
}
searchTypeList={searchTypeList}
// @TODO: How to hide the navigation list from field agents? Ask JPF
- navigationList={navigationList}
+ navigationList={canDoAdvanceSearch ? advancedSearchNavigationList : []}
searchHandler={(text, type) =>
props.router.navigate(
{
diff --git a/packages/client/src/components/form/FormFieldGenerator.tsx b/packages/client/src/components/form/FormFieldGenerator.tsx
index 9aa7c670e14..8876717769d 100644
--- a/packages/client/src/components/form/FormFieldGenerator.tsx
+++ b/packages/client/src/components/form/FormFieldGenerator.tsx
@@ -1104,7 +1104,8 @@ class FormSectionComponent extends React.Component {
}
}, {}),
intl,
- (location) => field.searchableType.includes(location.type)
+ (location) => field.searchableType.includes(location.type),
+ field.userOfficeId
)
}
: field
diff --git a/packages/client/src/forms/advancedSearch/fieldDefinitions/Birth.ts b/packages/client/src/forms/advancedSearch/fieldDefinitions/Birth.ts
index a99f4a20a4f..4ec75a035bd 100644
--- a/packages/client/src/forms/advancedSearch/fieldDefinitions/Birth.ts
+++ b/packages/client/src/forms/advancedSearch/fieldDefinitions/Birth.ts
@@ -14,8 +14,12 @@ import { formMessageDescriptors } from '@client/i18n/messages'
import { messages as advancedSearchForm } from '@client/i18n/messages/views/advancedSearchForm'
import { isValidDate } from '@client/search/advancedSearch/validators'
import { TIME_PERIOD } from './utils'
+import { UUID } from '@opencrvs/commons'
-const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
+const createBirthSearchRegistrationSection = (
+ hasBirthSearchJurisdictionScope?: boolean,
+ userOfficeId?: UUID
+): IFormSectionGroup => ({
id: 'BirthRegistrationDetails',
title: advancedSearchForm.registrationDetails,
fields: [
@@ -29,6 +33,9 @@ const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
initialValue: '',
searchableResource: ['locations', 'offices'],
searchableType: ['CRVS_OFFICE', 'ADMIN_STRUCTURE'],
+ ...(hasBirthSearchJurisdictionScope && {
+ userOfficeId
+ }),
validator: []
},
{
@@ -115,7 +122,7 @@ const advancedSearchBirthSectionRegistrationDetails: IFormSectionGroup = {
]
}
]
-}
+})
const advancedSearchBirthSectionChildDetails: IFormSectionGroup = {
id: 'BirthChildDetails',
@@ -420,11 +427,17 @@ const advancedSearchBirthSectionInformantDetails: IFormSectionGroup = {
]
}
-export const advancedSearchBirthSections = {
- birthSearchRegistrationSection: advancedSearchBirthSectionRegistrationDetails,
+export const createAdvancedSearchBirthSections = (
+ hasBirthSearchJurisdictionScope?: boolean,
+ userOfficeId?: UUID
+) => ({
+ birthSearchRegistrationSection: createBirthSearchRegistrationSection(
+ hasBirthSearchJurisdictionScope,
+ userOfficeId
+ ),
birthSearchChildSection: advancedSearchBirthSectionChildDetails,
birthSearchEventSection: advancedSearchBirthSectionEventDetails,
birthSearchMotherSection: advancedSearchBirthSectionMotherDetails,
birthSearchFatherSection: advancedSearchBirthSectionFatherDetails,
birthSearchInformantSection: advancedSearchBirthSectionInformantDetails
-}
+})
diff --git a/packages/client/src/forms/advancedSearch/fieldDefinitions/Death.ts b/packages/client/src/forms/advancedSearch/fieldDefinitions/Death.ts
index 7aa0ddb7248..ffe9b46d5c4 100644
--- a/packages/client/src/forms/advancedSearch/fieldDefinitions/Death.ts
+++ b/packages/client/src/forms/advancedSearch/fieldDefinitions/Death.ts
@@ -14,8 +14,12 @@ import { formMessageDescriptors } from '@client/i18n/messages'
import { messages as advancedSearchForm } from '@client/i18n/messages/views/advancedSearchForm'
import { isValidDate } from '@client/search/advancedSearch/validators'
import { TIME_PERIOD } from './utils'
+import { UUID } from '@opencrvs/commons'
-const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
+const createDeathSearchRegistrationSection = (
+ hasDeathSearchJurisdictionScope?: boolean,
+ userOfficeId?: UUID
+): IFormSectionGroup => ({
id: 'DeathRegistrationDetails',
title: advancedSearchForm.registrationDetails,
fields: [
@@ -29,6 +33,9 @@ const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
initialValue: '',
searchableResource: ['locations', 'offices'],
searchableType: ['CRVS_OFFICE', 'ADMIN_STRUCTURE'],
+ ...(hasDeathSearchJurisdictionScope && {
+ userOfficeId
+ }),
validator: []
},
{
@@ -115,7 +122,7 @@ const advancedSearchDeathSectionRegistrationDetails: IFormSectionGroup = {
]
}
]
-}
+})
const advancedSearchDeathSectiondeceasedDetails: IFormSectionGroup = {
id: 'DeathdeceasedDetails',
@@ -352,9 +359,15 @@ const advancedSearchDeathSectionInformantDetails: IFormSectionGroup = {
]
}
-export const advancedSearchDeathSections = {
- deathSearchRegistrationSection: advancedSearchDeathSectionRegistrationDetails,
+export const createAdvancedSearchDeathSections = (
+ hasDeathSearchJurisdictionScope?: boolean,
+ userOfficeId?: UUID
+) => ({
+ deathSearchRegistrationSection: createDeathSearchRegistrationSection(
+ hasDeathSearchJurisdictionScope,
+ userOfficeId
+ ),
deathSearchDeceasedSection: advancedSearchDeathSectiondeceasedDetails,
deathSearchEventSection: advancedSearchDeathSectionEventDetails,
deathSearchInformantSection: advancedSearchDeathSectionInformantDetails
-}
+})
diff --git a/packages/client/src/forms/index.ts b/packages/client/src/forms/index.ts
index 1b9ff99bf5c..c09ff1629b3 100644
--- a/packages/client/src/forms/index.ts
+++ b/packages/client/src/forms/index.ts
@@ -38,6 +38,7 @@ import {
NATIONAL_ID
} from '@client/utils/constants'
import { IconProps } from '@opencrvs/components/lib'
+import { UUID } from '@opencrvs/commons'
export const TEXT = 'TEXT'
export const TEL = 'TEL'
@@ -652,6 +653,7 @@ interface ILocationSearchInputFormField extends IFormFieldBase {
locationList?: ISearchLocation[]
searchableType: string[]
dispatchOptions?: IDispatchOptions
+ userOfficeId?: UUID // added to filter searchable location
dynamicOptions?: IDynamicOptions
}
diff --git a/packages/client/src/hooks/useAuthorization.ts b/packages/client/src/hooks/useAuthorization.ts
index e81c605dbcc..20fb17b480f 100644
--- a/packages/client/src/hooks/useAuthorization.ts
+++ b/packages/client/src/hooks/useAuthorization.ts
@@ -23,7 +23,7 @@ import {
isReviewableDeclaration,
isUpdatableDeclaration
} from '@client/declarations/utils'
-import { isUnderJurisdiction } from '@client/utils/locationUtils'
+import { isOfficeUnderJurisdiction } from '@client/utils/locationUtils'
import { getOfflineData } from '@client/offline/selectors'
import { IStoreState } from '@client/store'
@@ -90,6 +90,14 @@ export function usePermissions() {
const canSearchRecords = hasAnyScope(RECORD_SEARCH_SCOPES)
+ const hasBirthSearchJurisdictionScope = hasScope(
+ SCOPES.SEARCH_BIRTH_MY_JURISDICTION
+ )
+
+ const hasDeathSearchJurisdictionScope = hasScope(
+ SCOPES.SEARCH_DEATH_MY_JURISDICTION
+ )
+
const canDeclareRecords = hasAnyScope(RECORD_DECLARE_SCOPES)
const canReadUser = (user: Pick) => {
@@ -103,7 +111,7 @@ export function usePermissions() {
return user.primaryOffice.id === userPrimaryOffice?.id
}
if (hasScope(SCOPES.USER_READ_MY_JURISDICTION)) {
- return isUnderJurisdiction(
+ return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
user.primaryOffice.id,
locations,
@@ -130,7 +138,7 @@ export function usePermissions() {
if (roleScopes(user.role.id).includes(SCOPES.USER_UPDATE)) {
return false
}
- return isUnderJurisdiction(
+ return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
user.primaryOffice.id,
locations,
@@ -158,7 +166,7 @@ export function usePermissions() {
}
if (hasScope(SCOPES.ORGANISATION_READ_LOCATIONS_MY_JURISDICTION)) {
- return isUnderJurisdiction(
+ return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
office.id,
locations,
@@ -176,7 +184,7 @@ export function usePermissions() {
return true
}
if (hasScope(SCOPES.USER_CREATE_MY_JURISDICTION)) {
- return isUnderJurisdiction(
+ return isOfficeUnderJurisdiction(
userPrimaryOffice.id,
office.id,
locations,
@@ -242,6 +250,8 @@ export function usePermissions() {
canEditUser,
canCreateUser,
canAccessOffice,
+ hasBirthSearchJurisdictionScope,
+ hasDeathSearchJurisdictionScope,
canAddOfficeUsers,
canUpdateRecord,
canReviewRecord,
diff --git a/packages/client/src/search/advancedSearch/utils.ts b/packages/client/src/search/advancedSearch/utils.ts
index 04037c827c2..87e7e9865aa 100644
--- a/packages/client/src/search/advancedSearch/utils.ts
+++ b/packages/client/src/search/advancedSearch/utils.ts
@@ -9,8 +9,8 @@
* Copyright (C) The OpenCRVS Authors located at https://github.com/opencrvs/opencrvs-core/blob/master/AUTHORS.
*/
import { IAdvancedSearchParamState } from '@client/search/advancedSearch/reducer'
-import { advancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
-import { advancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
+import { createAdvancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
+import { createAdvancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
import { IDateRangePickerValue } from '@client/forms'
import { IAdvancedSearchResultMessages } from '@client/i18n/messages/views/advancedSearchResult'
import { constantsMessages, formMessages } from '@client/i18n/messages'
@@ -33,6 +33,7 @@ import {
isInvalidDate,
TIME_PERIOD
} from '@client/forms/advancedSearch/fieldDefinitions/utils'
+import { UUID } from '@opencrvs/commons'
export type advancedSearchPillKey = Exclude<
keyof IAdvancedSearchResultMessages,
@@ -43,21 +44,6 @@ type pillKeyValueMap = {
[key in advancedSearchPillKey]: string | undefined
}
-const {
- birthSearchRegistrationSection,
- birthSearchChildSection,
- birthSearchMotherSection,
- birthSearchFatherSection,
- birthSearchEventSection,
- birthSearchInformantSection
-} = advancedSearchBirthSections
-const {
- deathSearchRegistrationSection,
- deathSearchDeceasedSection,
- deathSearchEventSection,
- deathSearchInformantSection
-} = advancedSearchDeathSections
-
const baseKeysSameAsStore = [
'event',
'registrationStatuses',
@@ -405,8 +391,35 @@ export const transformStoreDataToAdvancedSearchLocalState = (
}
export const getAccordionActiveStateMap = (
- storeState: IAdvancedSearchParamState
+ storeState: IAdvancedSearchParamState,
+ hasBirthSearchJurisdictionScope?: boolean,
+ hasDeathSearchJurisdictionScope?: boolean,
+ officeId?: UUID
): Record => {
+ const advancedSearchBirthSections = createAdvancedSearchBirthSections(
+ hasBirthSearchJurisdictionScope,
+ officeId
+ )
+ const advancedSearchDeathSections = createAdvancedSearchDeathSections(
+ hasDeathSearchJurisdictionScope,
+ officeId
+ )
+ const {
+ birthSearchRegistrationSection,
+ birthSearchChildSection,
+ birthSearchMotherSection,
+ birthSearchFatherSection,
+ birthSearchEventSection,
+ birthSearchInformantSection
+ } = advancedSearchBirthSections
+
+ const {
+ deathSearchRegistrationSection,
+ deathSearchDeceasedSection,
+ deathSearchEventSection,
+ deathSearchInformantSection
+ } = advancedSearchDeathSections
+
return {
[birthSearchRegistrationSection.id]: Boolean(
storeState.declarationLocationId ||
diff --git a/packages/client/src/utils/locationUtils.test.ts b/packages/client/src/utils/locationUtils.test.ts
index 9570782e42e..e33a711c8e8 100644
--- a/packages/client/src/utils/locationUtils.test.ts
+++ b/packages/client/src/utils/locationUtils.test.ts
@@ -16,7 +16,7 @@ import {
filterLocations,
generateLocationName,
getJurisidictionType,
- isUnderJurisdiction,
+ isOfficeUnderJurisdiction,
getLocationNameMapOfFacility
} from '@client/utils/locationUtils'
import { createIntl } from 'react-intl'
@@ -181,13 +181,13 @@ describe('locationUtil tests', () => {
})
})
-describe('isUnderJurisdiction', () => {
+describe('isOfficeUnderJurisdiction', () => {
it('returns true if the other office is under jurisdiction of the given office', () => {
const officeId = '213ec5f3-e306-4f95-8058-f37893dbfbb6' // office in Chittagong
const otherOfficeId = '0d8474da-0361-4d32-979e-af91f012340a' // office in Chittagong -> Chandpur
expect(
- isUnderJurisdiction(
+ isOfficeUnderJurisdiction(
officeId,
otherOfficeId,
mockOfflineData.locations,
@@ -201,7 +201,7 @@ describe('isUnderJurisdiction', () => {
const otherOfficeId = '93259d69-71af-488f-8ada-32d06678df17' // office in Dhaka
expect(
- isUnderJurisdiction(
+ isOfficeUnderJurisdiction(
officeId,
otherOfficeId,
mockOfflineData.locations,
diff --git a/packages/client/src/utils/locationUtils.ts b/packages/client/src/utils/locationUtils.ts
index 075b5c40089..fdd720997b6 100644
--- a/packages/client/src/utils/locationUtils.ts
+++ b/packages/client/src/utils/locationUtils.ts
@@ -24,6 +24,7 @@ import { countries } from '@client/utils/countries'
import { lookup } from 'country-data'
import { getDefaultLanguage } from '@client/i18n/utils'
import { camelCase } from 'lodash'
+import { UUID } from '@opencrvs/commons'
export const countryAlpha3toAlpha2 = (isoCode: string): string | undefined => {
const alpha2 =
@@ -118,40 +119,48 @@ export function generateFullLocation(
export function generateSearchableLocations(
locations: ILocation[],
offlineLocations: { [key: string]: ILocation },
- intl: IntlShape
+ intl: IntlShape,
+ officeId?: UUID
) {
- const generated: ISearchLocation[] = locations.map((location: ILocation) => {
- let locationName = generateLocationName(location, intl)
+ const filteredLocations = officeId
+ ? getAssociatedLocationsAndOffices(officeId, locations)
+ : locations
+
+ const generated: ISearchLocation[] = filteredLocations.map(
+ (location: ILocation) => {
+ let locationName = generateLocationName(location, intl)
- if (
- location.partOf &&
- location.partOf !== 'Location/0' &&
- location.type !== 'CRVS_OFFICE'
- ) {
- const locRef = location.partOf.split('/')[1]
- let parent
if (
- (parent =
- offlineLocations[locRef] &&
- generateLocationName(offlineLocations[locRef], intl))
+ location.partOf &&
+ location.partOf !== 'Location/0' &&
+ location.type !== 'CRVS_OFFICE'
) {
- locationName += `, ${parent}`
+ const locRef = location.partOf.split('/')[1]
+ let parent
+ if (
+ (parent =
+ offlineLocations[locRef] &&
+ generateLocationName(offlineLocations[locRef], intl))
+ ) {
+ locationName += `, ${parent}`
+ }
}
- }
- return {
- id: location.id,
- searchableText: getLocalizedLocationName(intl, location),
- displayLabel: locationName
+ return {
+ id: location.id,
+ searchableText: getLocalizedLocationName(intl, location),
+ displayLabel: locationName
+ }
}
- })
+ )
return generated
}
export function generateLocations(
locations: { [key: string]: ILocation },
intl: IntlShape,
- filter?: (location: ILocation) => boolean
+ filter?: (location: ILocation) => boolean,
+ officeId?: UUID
) {
let locationArray = Object.values(locations)
@@ -159,7 +168,7 @@ export function generateLocations(
locationArray = locationArray.filter(filter)
}
- return generateSearchableLocations(locationArray, locations, intl)
+ return generateSearchableLocations(locationArray, locations, intl, officeId)
}
export function getJurisidictionType(
@@ -243,7 +252,7 @@ export function getLocationHierarchy(
})
}
-export function isUnderJurisdiction(
+export function isOfficeUnderJurisdiction(
officeId: string,
otherOfficeId: string,
locations: Record,
@@ -264,6 +273,37 @@ export function isUnderJurisdiction(
return Object.values(hierarchy).includes(parentLocation.id)
}
+function getAssociatedLocationsAndOffices(
+ officeId: string,
+ locations: ILocation[]
+): ILocation[] {
+ const office = locations.find(
+ (location) => location.id === officeId && location.type === 'CRVS_OFFICE'
+ )
+
+ if (!office) {
+ return []
+ }
+
+ const associatedLocations: ILocation[] = locations.filter((location) => {
+ let currentLocationId = office.partOf.split('/').at(1)
+
+ while (currentLocationId) {
+ const targetLocationId = currentLocationId
+ if (location.id === currentLocationId) {
+ return true
+ }
+
+ const nextLocation = locations.find((loc) => loc.id === targetLocationId)
+ currentLocationId = nextLocation?.partOf.split('/').at(1)
+ }
+
+ return false
+ })
+
+ return [office, ...associatedLocations]
+}
+
export function generateFullAddress(
address: Address,
offlineData: IOfflineData
diff --git a/packages/client/src/views/SearchResult/AdvancedSearch.test.tsx b/packages/client/src/views/SearchResult/AdvancedSearch.test.tsx
index 006230e1147..476822920e0 100644
--- a/packages/client/src/views/SearchResult/AdvancedSearch.test.tsx
+++ b/packages/client/src/views/SearchResult/AdvancedSearch.test.tsx
@@ -11,12 +11,17 @@
import { ADVANCED_SEARCH_RESULT } from '@client/navigation/routes'
import { setAdvancedSearchParam } from '@client/search/advancedSearch/actions'
import { createStore } from '@client/store'
-import { createTestComponent, setScopes } from '@client/tests/util'
+import {
+ createTestComponent,
+ mockUserResponse,
+ setScopes
+} from '@client/tests/util'
import { ReactWrapper } from 'enzyme'
import * as React from 'react'
import { createMemoryRouter } from 'react-router-dom'
import { AdvancedSearchConfig } from './AdvancedSearch'
import { SCOPES } from '@opencrvs/commons/client'
+import { setUserDetails } from '@client/profile/profileActions'
let testComponent: ReactWrapper
beforeEach(async () => {
@@ -53,6 +58,7 @@ describe('when advancedSearchPage renders with 2 or more active params in store'
let router: ReturnType
beforeEach(async () => {
const { store } = createStore()
+ setScopes([SCOPES.SEARCH_BIRTH, SCOPES.SEARCH_DEATH], store)
store.dispatch(
setAdvancedSearchParam({
event: 'birth',
@@ -60,6 +66,7 @@ describe('when advancedSearchPage renders with 2 or more active params in store'
registrationStatuses: ['IN_PROGRESS']
})
)
+ store.dispatch(setUserDetails(mockUserResponse as any))
;({ component: testComponent, router } = await createTestComponent(
,
{
diff --git a/packages/client/src/views/SearchResult/AdvancedSearch.tsx b/packages/client/src/views/SearchResult/AdvancedSearch.tsx
index 3d1b47ab507..93931b78389 100644
--- a/packages/client/src/views/SearchResult/AdvancedSearch.tsx
+++ b/packages/client/src/views/SearchResult/AdvancedSearch.tsx
@@ -13,7 +13,7 @@ import React, { useState } from 'react'
import { connect, useDispatch, useSelector } from 'react-redux'
import { injectIntl, useIntl } from 'react-intl'
-import { getScope } from '@client/profile/profileSelectors'
+import { getScope, getUserDetails } from '@client/profile/profileSelectors'
import { IStoreState } from '@client/store'
import { SysAdminContentWrapper } from '@client/views/SysAdmin/SysAdminContentWrapper'
import { messages } from '@client/i18n/messages/views/config'
@@ -22,8 +22,8 @@ import { Content, ContentSize, FormTabs } from '@opencrvs/components'
import { FormFieldGenerator } from '@client/components/form/FormFieldGenerator'
import { Button } from '@opencrvs/components/lib/Button'
import { Icon } from '@opencrvs/components/lib/Icon'
-import { advancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
-import { advancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
+import { createAdvancedSearchBirthSections } from '@client/forms/advancedSearch/fieldDefinitions/Birth'
+import { createAdvancedSearchDeathSections } from '@client/forms/advancedSearch/fieldDefinitions/Death'
import { buttonMessages } from '@client/i18n/messages'
import { messages as advancedSearchFormMessages } from '@client/i18n/messages/views/advancedSearchForm'
import { getAdvancedSearchParamsState as AdvancedSearchParamsSelector } from '@client/search/advancedSearch/advancedSearchSelectors'
@@ -45,6 +45,7 @@ import { advancedSearchInitialState } from '@client/search/advancedSearch/reduce
import { usePermissions } from '@client/hooks/useAuthorization'
import { useNavigate } from 'react-router-dom'
import * as routes from '@client/navigation/routes'
+import { UUID } from '@opencrvs/commons'
enum TabId {
BIRTH = 'birth',
@@ -55,21 +56,6 @@ const SearchButton = styled(Button)`
margin-top: 32px;
`
-const {
- birthSearchRegistrationSection,
- birthSearchChildSection,
- birthSearchMotherSection,
- birthSearchFatherSection,
- birthSearchEventSection,
- birthSearchInformantSection
-} = advancedSearchBirthSections
-const {
- deathSearchRegistrationSection,
- deathSearchDeceasedSection,
- deathSearchEventSection,
- deathSearchInformantSection
-} = advancedSearchDeathSections
-
export const isAdvancedSearchFormValid = (value: IAdvancedSearchFormState) => {
const validNonDateFields = Object.keys(value).filter(
(key) =>
@@ -107,7 +93,34 @@ export const isAdvancedSearchFormValid = (value: IAdvancedSearchFormState) => {
)
}
-const BirthSection = () => {
+interface BirthSectionProps {
+ hasBirthSearchJurisdictionScope: boolean
+ userOfficeId: UUID
+}
+
+interface DeathSectionProps {
+ hasDeathSearchJurisdictionScope: boolean
+ userOfficeId: UUID
+}
+
+const BirthSection: React.FC = ({
+ hasBirthSearchJurisdictionScope,
+ userOfficeId
+}) => {
+ const advancedSearchBirthSections = createAdvancedSearchBirthSections(
+ hasBirthSearchJurisdictionScope,
+ userOfficeId
+ )
+
+ const {
+ birthSearchRegistrationSection,
+ birthSearchChildSection,
+ birthSearchMotherSection,
+ birthSearchFatherSection,
+ birthSearchEventSection,
+ birthSearchInformantSection
+ } = advancedSearchBirthSections
+
const intl = useIntl()
const navigate = useNavigate()
const advancedSearchParamsState = useSelector(AdvancedSearchParamsSelector)
@@ -120,7 +133,12 @@ const BirthSection = () => {
)
})
const [accordionActiveStateMap] = useState(
- getAccordionActiveStateMap(advancedSearchParamsState)
+ getAccordionActiveStateMap(
+ advancedSearchParamsState,
+ hasBirthSearchJurisdictionScope,
+ undefined,
+ userOfficeId
+ )
)
const isDisabled = !isAdvancedSearchFormValid(formState)
@@ -319,7 +337,10 @@ const BirthSection = () => {
)
}
-const DeathSection = () => {
+const DeathSection: React.FC = ({
+ hasDeathSearchJurisdictionScope,
+ userOfficeId
+}) => {
const intl = useIntl()
const navigate = useNavigate()
const advancedSearchParamsState = useSelector(AdvancedSearchParamsSelector)
@@ -332,7 +353,12 @@ const DeathSection = () => {
)
})
const [accordionActiveStateMap] = useState(
- getAccordionActiveStateMap(advancedSearchParamsState)
+ getAccordionActiveStateMap(
+ advancedSearchParamsState,
+ undefined,
+ hasDeathSearchJurisdictionScope,
+ userOfficeId
+ )
)
const isDisable = !isAdvancedSearchFormValid(formState)
@@ -344,6 +370,18 @@ const DeathSection = () => {
advancedSearchFormMessages.hide
)
+ const advancedSearchDeathSections = createAdvancedSearchDeathSections(
+ hasDeathSearchJurisdictionScope,
+ userOfficeId
+ )
+
+ const {
+ deathSearchRegistrationSection,
+ deathSearchDeceasedSection,
+ deathSearchEventSection,
+ deathSearchInformantSection
+ } = advancedSearchDeathSections
+
return (
<>
{
const AdvancedSearch = () => {
const intl = useIntl()
- const { canSearchBirthRecords, canSearchDeathRecords } = usePermissions()
+ const {
+ canSearchBirthRecords,
+ canSearchDeathRecords,
+ hasBirthSearchJurisdictionScope,
+ hasDeathSearchJurisdictionScope
+ } = usePermissions()
const advancedSearchParamState = useSelector(AdvancedSearchParamsSelector)
+ const currentUser = useSelector(getUserDetails)
+ const userPrimaryOffice = currentUser?.primaryOffice
+
+ if (!userPrimaryOffice)
+ throw new Error(
+ 'Something went wrong. Could not find any office assigned to the user'
+ )
+
const activeTabId =
- advancedSearchParamState.event || canSearchBirthRecords
+ advancedSearchParamState.event === TabId.BIRTH && canSearchBirthRecords
+ ? TabId.BIRTH
+ : advancedSearchParamState.event === TabId.DEATH && canSearchDeathRecords
+ ? TabId.DEATH
+ : canSearchBirthRecords
? TabId.BIRTH
- : TabId.DEATH
+ : canSearchDeathRecords
+ ? TabId.DEATH
+ : ''
+
const dispatch = useDispatch()
const tabSections = [
{
@@ -537,8 +595,18 @@ const AdvancedSearch = () => {
}
subtitle={intl.formatMessage(messages.advancedSearchInstruction)}
>
- {activeTabId === TabId.BIRTH && }
- {activeTabId === TabId.DEATH && }
+ {activeTabId === TabId.BIRTH && (
+
+ )}
+ {activeTabId === TabId.DEATH && (
+
+ )}
>