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 && ( + + )}