From 4fee51b64e4c8a526ebfd3fc5bf089f0433511d0 Mon Sep 17 00:00:00 2001 From: Peter Muriuki Date: Mon, 18 Nov 2024 15:51:01 +0300 Subject: [PATCH] Refactor user management form fields and corresponding props config (#1500) * Refactor user management form fields and corresponding props config * Update tests --- .../src/components/CreateEditUser/index.tsx | 14 +- .../tests/extra-fields-user.test.tsx | 11 +- .../CreateEditUser/tests/fixtures.ts | 7 +- .../CreateEditUser/tests/index.test.tsx | 2 +- .../CreateEditUser/tests/new-user.test.tsx | 3 - .../src/components/CreateEditUser/index.tsx | 4 - .../tests/__snapshots__/index.test.tsx.snap | 18 +- .../CreateEditUser/tests/index.test.tsx | 98 +++--- .../src/components/forms/UserForm/index.tsx | 196 ++++++----- .../tests/__snapshots__/index.test.tsx.snap | 30 +- .../forms/UserForm/tests/index.test.tsx | 323 +++++------------- .../UserForm/tests/index.unmocked.test.tsx | 79 ++++- .../src/components/forms/UserForm/types.ts | 17 +- .../src/components/forms/UserForm/utils.tsx | 4 - .../keycloak-user-management/src/constants.ts | 12 +- .../keycloak-user-management/src/index.tsx | 1 + 16 files changed, 398 insertions(+), 421 deletions(-) diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx index cb547bbe8..ea999d6ab 100644 --- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx +++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/index.tsx @@ -5,6 +5,9 @@ import { FormFields, PRACTITIONER_USER_TYPE_CODE, SUPERVISOR_USER_TYPE_CODE, + commonFhirFields, + userTypeField, + FormFieldsKey, } from '@opensrp/user-management'; import { practitionerResourceType, @@ -356,13 +359,20 @@ export const practitionerUpdater = * @param props - component props */ export function CreateEditUser(props: CreateEditPropTypes) { - const extraFormFields = getConfig('projectCode') === 'giz' ? renderExtraFields : []; + let renderFormFields: FormFieldsKey[] = [...commonFhirFields]; + const projectCode = getConfig('projectCode'); + if (projectCode === 'giz') { + renderFormFields = [...commonFhirFields, ...renderExtraFields] as FormFieldsKey[]; + } else if (projectCode === 'eusm') { + renderFormFields = renderFormFields.filter((field) => field !== userTypeField); + } + const baseCompProps = { ...props, getPractitionerFun: getPractitioner, getPractitionerRoleFun: getPractitionerRole, postPutPractitionerFactory: practitionerUpdater, - extraFormFields: extraFormFields, + userFormRenderFields: renderFormFields, }; return ; diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx index dbf7f6c4a..0b6452c25 100644 --- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx +++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/extra-fields-user.test.tsx @@ -14,7 +14,7 @@ import { Provider } from 'react-redux'; import { store } from '@opensrp/store'; import nock from 'nock'; import { cleanup, fireEvent, render } from '@testing-library/react'; -import { waitFor } from '@testing-library/dom'; +import { waitFor, within } from '@testing-library/dom'; import { createMemoryHistory } from 'history'; import { authenticateUser } from '@onaio/session-reducer'; import fetch from 'jest-fetch-mock'; @@ -35,6 +35,9 @@ import { practitionerResourceType, practitionerRoleResourceType } from '../../.. import { fetchKeycloakUsers } from '@opensrp/user-management'; import { history } from '@onaio/connected-reducer-registry'; import { opensrpI18nInstance } from '@opensrp/i18n'; +import { setConfig } from '@opensrp/pkg-config'; + +setConfig('projectCode', 'giz'); jest.mock('fhirclient', () => { return jest.requireActual('fhirclient/lib/entry/browser'); @@ -245,11 +248,11 @@ test('renders correctly for edit user', async () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion userEvent.type(usernameInput!, 'flopo'); - // change mark as practitioner to tue - const yesMarkPractitioner = document.querySelectorAll('input[name="active"]')[0]; + const enabledFieldGroup = document.querySelector('#active') as HTMLElement; + const yesMarkPractitioner = within(enabledFieldGroup).getByRole('radio', { name: /yes/i }); userEvent.click(yesMarkPractitioner); - const markSupervisor = document.querySelectorAll('input[name="userType"]')[1]; + const markSupervisor = document.querySelector('input[value="supervisor"]') as HTMLElement; userEvent.click(markSupervisor); const submitButton = document.querySelector('button[type="submit"]'); diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts index 1fa379374..44e99d670 100644 --- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts +++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/fixtures.ts @@ -69,6 +69,7 @@ export const newPractitioner = { name: [{ use: 'official', family: 'plotus', given: ['flotus', ''] }], telecom: [{ system: 'email', value: 'flotus@plotus.duck' }], }; + export const newPractitionerRole = { resourceType: 'PractitionerRole', id: 'acb9d47e-7247-448f-be93-7a193a5312da', @@ -88,7 +89,11 @@ export const newPractitionerRole = { code: [ { coding: [ - { system: 'http://snomed.info/sct', code: '236321002', display: 'Supervisor (occupation)' }, + { + system: 'http://snomed.info/sct', + code: '405623001', + display: 'Assigned practitioner', + }, ], }, ], diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx index 3338117e7..d534ecf2e 100644 --- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx +++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/index.test.tsx @@ -230,7 +230,7 @@ test('renders correctly for edit user', async () => { const yesMarkPractitioner = document.querySelectorAll('input[name="active"]')[0]; userEvent.click(yesMarkPractitioner); - const markSupervisor = document.querySelectorAll('input[name="userType"]')[1]; + const markSupervisor = document.querySelector('input[value="supervisor"]') as HTMLElement; userEvent.click(markSupervisor); const submitButton = document.querySelector('button[type="submit"]'); diff --git a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx index 76ff2106b..387ffc797 100644 --- a/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx +++ b/packages/fhir-keycloak-user-management/src/components/CreateEditUser/tests/new-user.test.tsx @@ -234,9 +234,6 @@ test('renders correctly for new user', async () => { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion userEvent.type(usernameInput!, 'flopo'); - const markSupervisor = document.querySelectorAll('input[name="userType"]')[1]; - userEvent.click(markSupervisor); - const submitButton = document.querySelector('button[type="submit"]'); // find antd Select with id 'fhirCoreAppId' in the 'Form' component diff --git a/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx b/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx index 0becc1939..5e706b171 100644 --- a/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx +++ b/packages/keycloak-user-management/src/components/CreateEditUser/index.tsx @@ -51,7 +51,6 @@ export interface CreateEditUserProps { getPractitionerFun: (baseUrl: string, userId: string) => Promise; getPractitionerRoleFun?: (baseUrl: string, userId: string) => Promise; postPutPractitionerFactory: UserFormProps['practitionerUpdaterFactory']; - extraFormFields: string[]; } const getOpenSrpPractitioner = (baseUrl: string, userId: string) => { @@ -95,7 +94,6 @@ const CreateEditUser: React.FC = (props: CreateEditPropType getPractitionerFun, postPutPractitionerFactory, getPractitionerRoleFun, - extraFormFields, } = props; const userId = props.match.params[ROUTE_PARAM_USER_ID]; @@ -215,8 +213,6 @@ const CreateEditUser: React.FC = (props: CreateEditPropType hiddenFields={userFormHiddenFields} renderFields={userFormRenderFields} practitionerUpdaterFactory={postPutPractitionerFactory} - isFHIRInstance={!!getPractitionerRoleFun} - extraFormFields={extraFormFields} /> diff --git a/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap b/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap index 5c473d90e..d1eddca9c 100644 --- a/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap +++ b/packages/keycloak-user-management/src/components/CreateEditUser/tests/__snapshots__/index.test.tsx.snap @@ -1,5 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`components/CreateEditUser loads edit user page without breaking if user is not a practitioner 1`] = `"Edit User | opensrpFirst NameLast NameEmailUsernameUser TypePractitionerSupervisorEnable userYesNoMark as PractitionerYesNoKeycloak User GroupAdminAdmin 2New GroupĀ Application IDSaveCancel"`; + exports[`components/CreateEditUser renders correctly 1`] = ` Object { "children": ( + {children} +); + jest.mock('@opensrp/store', () => { const actualStore = jest.requireActual('@opensrp/store'); return { @@ -119,11 +126,13 @@ describe('components/CreateEditUser', () => { fetch.mockResponseOnce(JSON.stringify(requiredActions)); const wrapper = mount( - - - - - + + + + + + + ); await act(async () => { @@ -159,11 +168,13 @@ describe('components/CreateEditUser', () => { .once(JSON.stringify(practitioner1)); const wrapper = mount( - - - - - + + + + + + + ); await act(async () => { @@ -193,9 +204,11 @@ describe('components/CreateEditUser', () => { fetch.mockResponseOnce(JSON.stringify(keycloakUser)); const wrapper = mount( - - - + + + + + ); expect(wrapper.exists('.ant-spin')).toBeTruthy(); @@ -239,11 +252,13 @@ describe('components/CreateEditUser', () => { }; const wrapper = mount( - - - - - + + + + + + + ); // Loader should be displayed @@ -330,9 +345,11 @@ describe('components/CreateEditUser', () => { const wrapper = mount( - - - + + + + + ); @@ -345,8 +362,7 @@ describe('components/CreateEditUser', () => { }); expect(toJson(wrapper.find('.ant-spin'))).toBeFalsy(); // eslint-disable-next-line no-irregular-whitespace - const newLocal = `"Edit User | opensrpFirst NameLast NameEmailUsernameEnable userYesNoMark as PractitionerYesNoKeycloak User GroupAdminAdmin 2New GroupĀ SaveCancel"`; - expect(wrapper.text()).toMatchInlineSnapshot(newLocal); + expect(wrapper.text()).toMatchSnapshot(); wrapper.unmount(); }); @@ -376,11 +392,13 @@ describe('components/CreateEditUser', () => { }; const wrapper = mount( - - - - - + + + + + + + ); await act(async () => { @@ -408,11 +426,13 @@ describe('components/CreateEditUser', () => { ); const wrapper = mount( - - - - - + + + + + + + ); await act(async () => { @@ -438,11 +458,13 @@ describe('components/CreateEditUser', () => { .once(JSON.stringify(requiredActions)); const wrapper = mount( - - - - - + + + + + + + ); expect(wrapper.exists('.ant-spin')).toBeTruthy(); diff --git a/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx b/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx index 891aba897..9f7b4e2a7 100644 --- a/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx +++ b/packages/keycloak-user-management/src/components/forms/UserForm/index.tsx @@ -12,21 +12,23 @@ import { } from './utils'; import { sendErrorNotification } from '@opensrp/notifications'; import '../../../index.css'; -import { - CONTACT_FORM_FIELD, - FormFields, - FormFieldsKey, - SelectOption, - UserFormProps, -} from './types'; +import { FormFields, FormFieldsKey, SelectOption, UserFormProps } from './types'; import { SelectProps } from 'antd/lib/select'; import { useTranslation } from '../../../mls'; import { compositionResourceType, + emailField, + enabledField, + fhirCoreAppIdField, + firstNameField, + lastNameField, NATIONAL_ID_FORM_FIELD, PHONE_NUMBER_FORM_FIELD, PRACTITIONER, SUPERVISOR, + userGroupsField, + usernameField, + userTypeField, } from '../../../constants'; import { PaginatedAsyncSelect } from '@opensrp/react-utils'; import { IComposition } from '@smile-cdr/fhirts/dist/FHIR-R4/interfaces/IComposition'; @@ -41,10 +43,13 @@ const UserForm: FC = (props: UserFormProps) => { userGroups, renderFields, hiddenFields, - isFHIRInstance, - extraFormFields, } = props; - const shouldRender = (fieldName: FormFieldsKey) => !!renderFields?.includes(fieldName); + const shouldRender = (fieldName: FormFieldsKey) => { + if (renderFields === undefined) { + return true; + } + return !!renderFields.includes(fieldName); + }; const isHidden = (fieldName: FormFieldsKey) => !!hiddenFields?.includes(fieldName); const { t } = useTranslation(); @@ -147,26 +152,35 @@ const UserForm: FC = (props: UserFormProps) => { .finally(() => setSubmitting(false)); }} > - - - - - - - {extraFormFields.includes(NATIONAL_ID_FORM_FIELD) && ( + {shouldRender(firstNameField) ? ( + + ) : null} + + {shouldRender(lastNameField) ? ( + + ) : null} + + {shouldRender(NATIONAL_ID_FORM_FIELD) ? ( - )} - {extraFormFields.includes(PHONE_NUMBER_FORM_FIELD) && ( + ) : null} + + {shouldRender(PHONE_NUMBER_FORM_FIELD) ? ( - )} - - - - - - + ) : null} - {shouldRender(CONTACT_FORM_FIELD) ? ( + {shouldRender(emailField) ? ( + + + + ) : null} + + {shouldRender(usernameField) ? ( ) : null} - {isFHIRInstance ? ( - + {shouldRender(userTypeField) ? ( + ) : null} - + - {initialValues.id && initialValues.id !== extraData.user_id ? ( - + {initialValues.id && + initialValues.id !== extraData.user_id && + shouldRender('active') ? ( + ) : null} - - - mode="multiple" - allowClear - placeholder={t('Please select')} - style={{ width: '100%' }} - options={getUserGroupsOptions(userGroups)} - filterOption={userGroupOptionsFilter as SelectProps['filterOption']} - > - + {shouldRender(userGroupsField) ? ( + + ) : null} - {isFHIRInstance ? ( + {shouldRender(fhirCoreAppIdField) ? (