diff --git a/package.json b/package.json index 24f0acf64..48295e7ad 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,6 @@ "*.{js,jsx,ts,tsx}": "eslint --cache --fix" }, "dependencies": { - "@carbon/charts-react": "^1.13.33", "@hookform/resolvers": "^3.1.1", "ace-builds": "^1.36.5", "classnames": "^2.3.2", diff --git a/packages/esm-admin-app/package.json b/packages/esm-admin-app/package.json index 1d2de7093..1422f39ed 100644 --- a/packages/esm-admin-app/package.json +++ b/packages/esm-admin-app/package.json @@ -37,11 +37,11 @@ "url": "https://github.com/palladiumkenya/kenyaemr-esm-3.x/issues" }, "dependencies": { - "@carbon/react": "^1.72.0", "lodash-es": "^4.17.15", "react-to-print": "^2.14.13" }, "peerDependencies": { + "@carbon/react": "1.x", "@openmrs/esm-framework": "5.x", "react": "^18.1.0", "react-i18next": "11.x", diff --git a/packages/esm-admin-app/src/components/facility-setup/facility-info.component.tsx b/packages/esm-admin-app/src/components/facility-setup/facility-info.component.tsx new file mode 100644 index 000000000..ed5d08831 --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/facility-info.component.tsx @@ -0,0 +1,118 @@ +import React, { useEffect, useState } from 'react'; +import { Tile, Grid, Column, Layer, InlineLoading, Button } from '@carbon/react'; +import { useFacilityInfo } from '../hook/useFacilityInfo'; +import styles from './facility-info.scss'; +import { useTranslation } from 'react-i18next'; +import { showNotification, showSnackbar } from '@openmrs/esm-framework'; +import { FacilityData } from '../../types'; + +const FacilityInfo: React.FC = () => { + const { t } = useTranslation(); + const [shouldSynchronize, setshouldSynchronize] = useState(false); + const { defaultFacility, isLoading: defaultFacilityLoading, error, refetch } = useFacilityInfo(shouldSynchronize); + + const [facilityData, setFacilityData] = useState(defaultFacility); + useEffect(() => { + setFacilityData(defaultFacility); + }, [defaultFacility]); + + const synchronizeFacilityData = async () => { + try { + setshouldSynchronize(true); + await refetch(); + showSnackbar({ + title: t('syncingHieSuccess', 'Synchronization Complete'), + kind: 'success', + isLowContrast: true, + }); + if (defaultFacility?.source != 'HIE') { + showSnackbar({ + kind: 'warning', + title: 'HIE Sync Failed. Pulling local info.', + isLowContrast: true, + }); + } + } catch (error) { + const errorMessage = error?.responseBody?.error?.message ?? 'An error occurred while synchronizing with HIE'; + showSnackbar({ + title: t('syncingHieError', 'Syncing with HIE Failed'), + subtitle: errorMessage, + kind: 'error', + isLowContrast: true, + }); + } + }; + + return ( +
+
+ + {defaultFacilityLoading ? ( + + ) : ( + + )} + +
+ + + {/* General Info Column */} + + +

General Information

+
+
+

+ Facility Name: {facilityData?.display} +

+

+ Facility KMHFR Code: {facilityData?.mflCode} +

+

+ Keph Level: {facilityData?.shaKephLevel} +

+
+
+
+
+
+ + {/* SHA Info Column */} + + + +

SHA Information

+
+
+

+ Facility Registry Code: {facilityData?.shaFacilityId} +

+

+ SHA License Number: {facilityData?.shaFacilityLicenseNumber} +

+

+ SHA Status: {facilityData?.operationalStatus} +

+

+ SHA Contracted: {facilityData?.shaContracted} +

+

+ SHA Expiry Date: {facilityData?.shaFacilityExpiryDate} +

+
+
+
+
+
+
+ ); +}; + +export default FacilityInfo; diff --git a/packages/esm-admin-app/src/components/facility-setup/facility-info.scss b/packages/esm-admin-app/src/components/facility-setup/facility-info.scss new file mode 100644 index 000000000..27fc2f244 --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/facility-info.scss @@ -0,0 +1,87 @@ +@use '@carbon/layout'; +@use '@carbon/type'; +@use '@carbon/colors'; + +.omrs-main-content { + background-color: colors.$white; +} + +.bottomBorder { + margin-bottom: layout.$spacing-05; +} + +.btnLayer { + display: flex; + padding-top: layout.$spacing-05; + padding-right: layout.$spacing-05; + padding-bottom: layout.$spacing-05; + margin-top: layout.$spacing-05; + flex-direction: row; + justify-content: flex-end; + background-color: white; + width: 100%; +} + +.tableLayer { + padding-left: layout.$spacing-05; + padding-right: layout.$spacing-05; + background: white; + padding-top: layout.$spacing-01; +} + +.loading { + display: flex; + padding-top: layout.$spacing-05; + padding-right: layout.$spacing-05; + padding-bottom: layout.$spacing-05; + margin-top: layout.$spacing-05; + flex-direction: row; + justify-content: flex-end; + background-color: white; + width: 100%; +} + +.facilityInfoContainer { + margin: layout.$spacing-05; +} + +.card { + padding: 1rem; + background-color: colors.$gray-10; + border: 1px solid #e0e0e0; + border-radius: 2px; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); +} + +.cardTitle { + margin-bottom: 1rem; + font-size: 1.25rem; + font-weight: 600; +} + +.cardDivider { + border: none; + border-top: 1px solid #e0e0e0; + margin: 0.5rem 0; +} +.cardContent { + font-size: 1rem; + line-height: 1.8; +} + +.cardContent p { + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; +} +.cardContent br { + display: flex; + justify-content: space-between; + margin-bottom: 0.5rem; +} + +.cardContent strong { + min-width: 150px; + display: inline-block; + color: #393939; +} diff --git a/packages/esm-admin-app/src/components/facility-setup/facility-setup.component.tsx b/packages/esm-admin-app/src/components/facility-setup/facility-setup.component.tsx new file mode 100644 index 000000000..467262137 --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/facility-setup.component.tsx @@ -0,0 +1,22 @@ +import React, { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Layer, Button, MenuItem, InlineLoading } from '@carbon/react'; +import styles from './facility-setup.scss'; +import FacilityInfo from './facility-info.component'; +import Header from './header/header.component'; +import { showSnackbar } from '@openmrs/esm-framework'; + +const FacilitySetup: React.FC = () => { + const { t } = useTranslation(); + return ( +
+
+ + + + +
+ ); +}; + +export default FacilitySetup; diff --git a/packages/esm-admin-app/src/components/facility-setup/facility-setup.scss b/packages/esm-admin-app/src/components/facility-setup/facility-setup.scss new file mode 100644 index 000000000..4407b7dd4 --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/facility-setup.scss @@ -0,0 +1,38 @@ +@use '@carbon/layout'; +@use '@carbon/type'; +@use '@carbon/colors'; + +.omrs-main-content { + background-color: white; +} + +.btnLayer { + display: flex; + padding-top: layout.$spacing-05; + padding-right: layout.$spacing-05; + padding-bottom: layout.$spacing-05; + margin-top: layout.$spacing-05; + flex-direction: row; + justify-content: flex-end; + background-color: white; + width: 100%; +} + +.tableLayer { + padding-left: layout.$spacing-05; + padding-right: layout.$spacing-05; + background: white; + padding-top: layout.$spacing-01; +} + +.loading { + display: flex; + padding-top: layout.$spacing-05; + padding-right: layout.$spacing-05; + padding-bottom: layout.$spacing-05; + margin-top: layout.$spacing-05; + flex-direction: row; + justify-content: flex-end; + background-color: white; + width: 100%; +} diff --git a/packages/esm-admin-app/src/components/facility-setup/header/header.component.tsx b/packages/esm-admin-app/src/components/facility-setup/header/header.component.tsx new file mode 100644 index 000000000..ae276726c --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/header/header.component.tsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { Development } from '@carbon/react/icons'; +import { useSession, PageHeader } from '@openmrs/esm-framework'; +import styles from './header.scss'; + +interface HeaderProps { + title: string; +} + +const Header: React.FC = ({ title }) => { + const { t } = useTranslation(); + const session = useSession(); + const location = session?.sessionLocation?.display; + + return ( +
+ } className={styles.header} /> +
+ ); +}; + +export default Header; diff --git a/packages/esm-admin-app/src/components/facility-setup/header/header.scss b/packages/esm-admin-app/src/components/facility-setup/header/header.scss new file mode 100644 index 000000000..907b58f6b --- /dev/null +++ b/packages/esm-admin-app/src/components/facility-setup/header/header.scss @@ -0,0 +1,19 @@ +@use '@carbon/layout'; +@use '@carbon/type'; +@use '@carbon/colors'; + +.header { + @include type.type-style('body-compact-02'); + height: layout.$spacing-12; + display: flex; + justify-content: space-between; + padding: layout.$spacing-05; + background: white; + border: 1px solid colors.$gray-20; +} +.svgContainer svg { + width: layout.$spacing-10; + height: layout.$spacing-10; + margin-right: layout.$spacing-06; + fill: var(--brand-03); +} diff --git a/packages/esm-admin-app/src/components/hook/useFacilityInfo.tsx b/packages/esm-admin-app/src/components/hook/useFacilityInfo.tsx new file mode 100644 index 000000000..a3c60a681 --- /dev/null +++ b/packages/esm-admin-app/src/components/hook/useFacilityInfo.tsx @@ -0,0 +1,21 @@ +import { FetchResponse, openmrsFetch, restBaseUrl, useSession } from '@openmrs/esm-framework'; +import useSWR from 'swr'; +import { FacilityData } from '../../types'; + +export function useFacilityInfo(shouldSynchronize: boolean = false) { + const { authenticated } = useSession(); + const url = `${restBaseUrl}/kenyaemr/default-facility?synchronize=${shouldSynchronize}`; + + const { data, isLoading, error, mutate } = useSWR>( + authenticated ? url : null, + openmrsFetch, + {}, + ); + + return { + isLoading, + defaultFacility: data?.data, + error, + refetch: mutate, // Expose mutate as refetch + }; +} diff --git a/packages/esm-admin-app/src/components/logs-table/operation-log-table.component.tsx b/packages/esm-admin-app/src/components/logs-table/operation-log-table.component.tsx index f572b80e0..33e1fb5fe 100644 --- a/packages/esm-admin-app/src/components/logs-table/operation-log-table.component.tsx +++ b/packages/esm-admin-app/src/components/logs-table/operation-log-table.component.tsx @@ -49,7 +49,7 @@ const LogTable: React.FC = ({ logData, isLoading }) => { return (
- +
{isLoading && logData.length === 0 ? ( = ({ closeWorkspace, promptBeforeClosing, @@ -59,83 +69,79 @@ const ManageUserWorkspace: React.FC = ({ const isTablet = useLayoutType() === 'tablet'; const [activeSection, setActiveSection] = useState('demographic'); const [currentIndex, setCurrentIndex] = useState(0); + const { provider = [], loadingProvider, providerError } = useProvider(initialUserValue.systemId); + const { location, loadingLocation } = useLocation(); const { userManagementFormSchema } = UserManagementFormSchema(); + const { + types: { results: stockOperations }, + loadingStock, + } = useStockOperationTypes(); + + const { stockLocations } = useStockTagLocations(); const { providerAttributeType = [] } = useProviderAttributeType(); - const providerLicenseAttributeType = - providerAttributeType.find((type) => type.name === 'Practising License Number')?.uuid || ''; - const licenseExpiryDateAttributeType = - providerAttributeType.find((type) => type.name === 'License Expiry Date')?.uuid || ''; - const primaryFacilityAttributeType = - providerAttributeType.find((type) => type.name === 'Primary Facility')?.uuid || ''; - const { provider = [], loadingProvider, providerError } = useProvider(initialUserValue.systemId); - const { location, loadingLocation } = useLocation(); + const { roles = [], isLoading } = useRoles(); + const { rolesConfig, error } = useSystemUserRoleConfigSetting(); + const { attributeTypes = [] } = usePersonAttribute(); + // Memoize provider attribute mappings + const attributeTypeMapping = useMemo(() => { + return { + licenseNumber: + providerAttributeType.find((type) => type.uuid === 'bcaaa67b-cc72-4662-90c2-e1e992ceda66')?.uuid || '', + licenseExpiry: + providerAttributeType.find((type) => type.uuid === '00539959-a1c7-4848-a5ed-8941e9d5e835')?.uuid || '', + primaryFacility: + providerAttributeType.find((type) => type.uuid === '5a53dddd-b382-4245-9bf1-03bce973f24b')?.uuid || '', + }; + }, [providerAttributeType]); - function getProviderAttributes() { - if (!Array.isArray(provider)) { - return []; - } - return provider.flatMap((item) => item.attributes || []); - } + const providerAttributes = useMemo(() => provider.flatMap((item) => item.attributes || []), [provider]); - function getProviderLicenseNumber() { - const providerAttributes = getProviderAttributes(); - const providerLicense = providerAttributes.find( - (attr) => attr.attributeType?.uuid === providerLicenseAttributeType && attr.value, - ); - return providerLicense?.value; - } + const getProviderAttributeValue = useCallback( + (uuid: string, key = 'value') => providerAttributes.find((attr) => attr.attributeType?.uuid === uuid)?.[key], + [providerAttributes], + ); - function getPrimaryFacility() { - const providerAttributes = getProviderAttributes(); - const primaryFacility = providerAttributes.find( - (attr) => attr.attributeType?.uuid === primaryFacilityAttributeType && attr.value, - ); - if (primaryFacility && primaryFacility.value) { - if (typeof primaryFacility.value === 'object' && primaryFacility.value !== null) { - return primaryFacility.value?.name; - } - } - } + const providerLicenseNumber = useMemo( + () => getProviderAttributeValue(attributeTypeMapping.licenseNumber), + [attributeTypeMapping, getProviderAttributeValue], + ); - function getProviderLicenseExpiryDate() { - const providerAttributes = getProviderAttributes(); - const licenseExpiryDate = providerAttributes.find( - (attr) => attr.attributeType?.uuid === licenseExpiryDateAttributeType && attr.value, - ); - - if (licenseExpiryDate?.value) { - const date = new Date(licenseExpiryDate.value); - return [ - date.getFullYear(), - String(date.getMonth() + 1).padStart(2, '0'), - String(date.getDate()).padStart(2, '0'), - ].join('-'); - } - } + const primaryFacility = useMemo(() => { + const value = getProviderAttributeValue(attributeTypeMapping.primaryFacility); + return typeof value === 'object' ? value?.name : value; + }, [attributeTypeMapping, getProviderAttributeValue]); + + const licenseExpiryDate = useMemo(() => { + const value = getProviderAttributeValue(attributeTypeMapping.licenseExpiry); + return value ? new Date(value).toISOString().split('T')[0] : undefined; + }, [attributeTypeMapping, getProviderAttributeValue]); const isInitialValuesEmpty = Object.keys(initialUserValue).length === 0; type UserFormSchema = z.infer; - const formDefaultValues = !isInitialValuesEmpty - ? { - ...initialUserValue, - ...extractNameParts(initialUserValue.person?.display || ''), - phoneNumber: extractAttributeValue(initialUserValue.person?.attributes, 'Telephone'), - email: extractAttributeValue(initialUserValue.person?.attributes, 'Email'), - roles: - initialUserValue.roles?.map((role) => ({ - uuid: role.uuid, - display: role.display, - description: role.description, - })) || [], - gender: initialUserValue.person?.gender || 'M', - providerLicense: getProviderLicenseNumber(), - licenseExpiryDate: getProviderLicenseExpiryDate(), - primaryFacility: getPrimaryFacility(), - } - : {}; + const formDefaultValues = useMemo(() => { + if (isInitialValuesEmpty) { + return {}; + } + return { + ...initialUserValue, + ...extractNameParts(initialUserValue.person?.display || ''), + phoneNumber: extractAttributeValue(initialUserValue.person?.attributes, 'Telephone'), + email: extractAttributeValue(initialUserValue.person?.attributes, 'Email'), + roles: + initialUserValue.roles?.map((role) => ({ + uuid: role.uuid, + display: role.display, + description: role.description, + })) || [], + gender: initialUserValue.person?.gender, + providerLicense: providerLicenseNumber, + licenseExpiryDate: licenseExpiryDate, + primaryFacility: primaryFacility, + }; + }, [isInitialValuesEmpty, initialUserValue, providerLicenseNumber, licenseExpiryDate, primaryFacility]); function extractNameParts(display = '') { const nameParts = display.split(' '); @@ -146,7 +152,7 @@ const ManageUserWorkspace: React.FC = ({ return { givenName, middleName, familyName }; } - function extractAttributeValue(attributes, prefix) { + function extractAttributeValue(attributes, prefix: string) { return attributes?.find((attr) => attr.display.startsWith(prefix))?.display?.split(' ')[3] || ''; } @@ -156,11 +162,15 @@ const ManageUserWorkspace: React.FC = ({ defaultValues: formDefaultValues, }); + const { reset } = userFormMethods; + const { errors, isSubmitting, isDirty } = userFormMethods.formState; - const { roles = [], isLoading } = useRoles(); - const { rolesConfig, error } = useSystemUserRoleConfigSetting(); - const { attributeTypes = [] } = usePersonAttribute(); + useEffect(() => { + if (!loadingProvider && !loadingLocation) { + reset(formDefaultValues); + } + }, [loadingProvider, loadingLocation, formDefaultValues, reset]); useEffect(() => { if (isDirty) { @@ -169,50 +179,62 @@ const ManageUserWorkspace: React.FC = ({ }, [isDirty, promptBeforeClosing]); const onSubmit = async (data: UserFormSchema) => { - const emailAttribute = attributeTypes.find((attr) => attr.name === 'Email address')?.uuid || ''; - const telephoneAttribute = attributeTypes.find((attr) => attr.name === 'Telephone contact')?.uuid || ''; + const emailAttribute = 'b8d0b331-1d2d-4a9a-b741-1816f498bdb6'; + const telephoneAttribute = 'b2c38640-2603-4629-aebd-3b54f33f1e3a'; const setProvider = data.providerIdentifiers; - const facility = data.primaryFacility.split(' '); - const mflCode = facility[facility.length - 1]; - const providerUUID = provider[0].uuid; + const editProvider = data.isEditProvider; + const providerUUID = provider[0]?.uuid || ''; + const roleName = data.roles?.[0]?.display || ''; + + const hasValidLocations = Array.isArray(data.operationLocation) && data.operationLocation.length > 0; + const hasEnabledFlag = data.enabled !== undefined && data.enabled !== null; + const hasOperationTypes = Array.isArray(data.stockOperation) && data.stockOperation.length > 0; + const hasDateRange = data.activeFrom && data.activeTo; + const hasValidRoleConditions = + hasValidLocations && hasEnabledFlag && hasOperationTypes && (data.permanent || hasDateRange); + + const userRoleScopePayload: Partial = { + ...(hasValidRoleConditions && { role: roleName }), + locations: hasValidLocations + ? data.operationLocation.map((loc) => ({ + locationUuid: loc.locationUuid, + locationName: loc.locationName, + enableDescendants: false, + })) + : [], + permanent: data.permanent, + enabled: data.enabled, + activeFrom: data.activeFrom, + activeTo: data.activeTo, + operationTypes: hasOperationTypes + ? data.stockOperation.map((op) => ({ + operationTypeUuid: op.operationTypeUuid, + operationTypeName: op.operationTypeName, + })) + : [], + }; + + if (!hasValidRoleConditions && userRoleScopePayload.locations.length === 0) { + return null; + } + const providerPayload: Partial = { attributes: [ - { - attributeType: primaryFacilityAttributeType, - value: mflCode, - }, - { - attributeType: providerLicenseAttributeType, - value: data.providerLicense, - }, - { - attributeType: licenseExpiryDateAttributeType, - value: data.licenseExpiryDate, - }, - ], + { attributeType: attributeTypeMapping.primaryFacility, value: data.primaryFacility?.split(' ').pop() || '' }, + { attributeType: attributeTypeMapping.licenseNumber, value: data.providerLicense }, + { attributeType: attributeTypeMapping.licenseExpiry, value: data.licenseExpiryDate }, + ].filter((attr) => attr.value), }; const payload: Partial = { username: data.username, password: data.password, person: { - names: [ - { - givenName: data.givenName, - familyName: data.familyName, - middleName: data.middleName, - }, - ], + names: [{ givenName: data.givenName, familyName: data.familyName, middleName: data.middleName }], gender: data.gender, attributes: [ - { - attributeType: telephoneAttribute, - value: data.phoneNumber, - }, - { - attributeType: emailAttribute, - value: data.email, - }, + { attributeType: telephoneAttribute, value: data.phoneNumber }, + { attributeType: emailAttribute, value: data.email }, ], }, roles: data.roles.map((role) => ({ @@ -222,45 +244,75 @@ const ManageUserWorkspace: React.FC = ({ })), }; - try { - const response = await createUser( - payload, - setProvider, - providerPayload, - initialUserValue?.uuid ?? '', - providerUUID ?? '', - ); + const showSnackbarMessage = (title: string, subtitle: string, kind: 'success' | 'error') => { + showSnackbar({ title, subtitle, kind, isLowContrast: true }); + }; - if (response.ok) { - showSnackbar({ - title: t('userSaved', 'User saved successfully'), - kind: 'success', - isLowContrast: true, - }); + try { + const response = await createUser(payload, initialUserValue?.uuid || ''); + if (response.uuid) { + showSnackbarMessage(t('userSaved', 'User saved successfully'), '', 'success'); handleMutation( `${restBaseUrl}/user?v=custom:(uuid,username,display,systemId,retired,person:(uuid,display,gender,names:(givenName,familyName,middleName),attributes:(uuid,display)),roles:(uuid,description,display,name))`, ); closeWorkspaceWithSavedChanges(); + + if (userRoleScopePayload && Object.keys(userRoleScopePayload).length > 0) { + try { + const userRoleScopeUrl = `${restBaseUrl}/stockmanagement/userrolescope`; + const userUuid = response.uuid; + + const userRoleScopeResponse = await createOrUpdateUserRoleScope( + userRoleScopeUrl, + userRoleScopePayload, + userUuid, + ); + + if (userRoleScopeResponse.ok) { + showSnackbarMessage(t('userRoleScopeSaved', 'User role scope saved successfully'), '', 'success'); + } + } catch (error) { + showSnackbarMessage( + t('userRoleScopeFail', 'Failed to save user role scope'), + t('userRoleScopeFailedSubtitle', 'An error occurred while creating user role scope'), + 'error', + ); + } + } + if (setProvider || editProvider) { + try { + const providerUrl = providerUUID ? `${restBaseUrl}/provider/${providerUUID}` : `${restBaseUrl}/provider`; + const personUUID = response.person.uuid; + const identifier = response.systemId; + const providerResponse = await createProvider(personUUID, identifier, providerPayload, providerUrl); + + if (providerResponse.ok) { + showSnackbarMessage(t('providerSaved', 'Provider saved successfully'), '', 'success'); + } + } catch (error) { + showSnackbarMessage( + t('providerFail', 'Failed to save provider'), + t('providerFailedSubtitle', 'An error occurred while creating provider'), + 'error', + ); + } + } + } else { + throw new Error('User creation failed'); } } catch (error) { - const errorObject = error?.responseBody?.error; - const errorMessage = errorObject?.message ?? 'An error occurred while creating user'; - - showSnackbar({ - title: t('userSaveFailed', 'Failed to save user'), - subtitle: t('userCreationFailedSubtitle', 'An error occurred while creating user {{errorMessage}}', { - errorMessage, - }), - kind: 'error', - isLowContrast: true, - }); + showSnackbarMessage( + t('userSaveFailed', 'Failed to save user'), + t('userCreationFailedSubtitle', 'An error occurred while saving user form '), + 'error', + ); } }; - const handleError = (error) => { + const handleError = (error, response) => { showSnackbar({ - title: t('userSaveFailed', 'Failed to save user'), + title: t('userSaveFailed', 'Fail to save {{error}}', response), subtitle: t('userCreationFailedSubtitle', 'An error occurred while creating user {{errorMessage}}', { errorMessage: JSON.stringify(error, null, 2), }), @@ -279,12 +331,16 @@ const ManageUserWorkspace: React.FC = ({ setActiveSection((prev) => (prev !== section ? section : prev)); }; - const steps = [ - { id: 'demographic', label: t('demographicInformation', 'Demographic Info') }, - { id: 'provider', label: t('providerAccount', 'Provider Account') }, - { id: 'login', label: t('loginInformation', 'Login Info') }, - { id: 'roles', label: t('roles', 'Roles Info') }, - ]; + const steps = useMemo( + () => [ + { id: 'demographic', label: t('demographicInformation', 'Demographic Info') }, + { id: 'provider', label: t('providerAccount', 'Provider Account') }, + { id: 'login', label: t('loginInformation', 'Login Info') }, + { id: 'roles', label: t('roles', 'Roles Info') }, + { id: 'additionalRoles', label: t('additionalRoles', 'Additional Roles') }, + ], + [t], + ); return (
@@ -532,6 +588,26 @@ const ManageUserWorkspace: React.FC = ({ )} /> + + ( + + field.onChange(e.target.checked)} + /> + + )} + /> + ) : ( <> @@ -759,73 +835,375 @@ const ManageUserWorkspace: React.FC = ({ - {rolesConfig.map((category) => ( - - - {isLoading ? ( - - ) : ( - { - const selectedRoles = field.value || []; - - return ( - <> - {roles - .filter((role) => category.roles.includes(role.name)) - .map((role) => { - const isSelected = selectedRoles.some( - (r) => - r.display === role.display && - r.description === role.description && - r.uuid === role.uuid, - ); - - return ( - - ); - })} - - ); - }} - /> + {rolesConfig + .filter((category) => category.category !== 'Inventory Roles') + .map((category) => ( + + + {isLoading ? ( + + ) : ( + { + const selectedRoles = field.value || []; + + return ( + <> + {roles + .filter((role) => category.roles.includes(role.name)) + .map((role) => { + const isSelected = selectedRoles.some( + (r) => + r.display === role.display && + r.description === role.description && + r.uuid === role.uuid, + ); + + return ( + + ); + })} + + ); + }} + /> + )} + + + ))} + + + )} + + {/* Additional roles */} + {activeSection === 'additionalRoles' && ( + + + + + + + {rolesConfig + .filter((category) => category.category === 'Inventory Roles') + .map((category) => ( + + + {isLoading ? ( + + ) : ( + { + const selectedRoles = field.value || []; + + return ( + <> + {roles + .filter((role) => category.roles.includes(role.name)) + .map((role) => { + const isSelected = selectedRoles.some( + (r) => + r.display === role.display && + r.description === role.description && + r.uuid === role.uuid, + ); + + return ( + + ); + })} + + ); + }} + /> + )} + + + ))} + + + + + + {loadingStock ? ( + + ) : ( + { + const selectedStockOperation = field.value || []; + const isSelected = (operationUuid: string) => + selectedStockOperation.some((op) => op.operationTypeUuid === operationUuid); + const toggleOperation = (operation) => { + if (isSelected(operation.uuid)) { + field.onChange( + selectedStockOperation.filter( + (op) => op.operationTypeUuid !== operation.uuid, + ), + ); + } else { + field.onChange([ + ...selectedStockOperation, + { + operationTypeUuid: operation.uuid, + operationTypeName: operation.name, + }, + ]); + } + }; + + return ( + <> + {stockOperations?.length > 0 && + stockOperations.map((operation) => { + return ( + + ); + })} + + ); + }} + /> + )} + + + + + + + {loadingStock ? ( + + ) : ( + { + const selectedLocations = field.value || []; + const isSelected = (locationUuid: string) => + selectedLocations.some((loc) => loc.locationUuid === locationUuid); + const toggleLocation = (location) => { + if (isSelected(location.id)) { + field.onChange( + selectedLocations.filter((loc) => loc.locationUuid !== location.id), + ); + } else { + field.onChange([ + ...selectedLocations, + { locationName: location.name, locationUuid: location.id }, + ]); + } + }; + + return ( + <> + {stockLocations?.length > 0 && + stockLocations.map((location) => ( + + ))} + + ); + }} + /> + )} + + + + + + + ( +
+ +
)} -
-
- ))} + /> + ( +
+ +
+ )} + /> + + +
+ + + {!userFormMethods?.watch('permanent') && ( + + { + if (Array.isArray(dates) && dates.length === 2) { + userFormMethods.setValue('activeFrom', dates[0]); + userFormMethods.setValue('activeTo', dates[1]); + } + }}> + + + + + } + /> + } + /> + + )}
)} diff --git a/packages/esm-admin-app/src/components/users/userManagementFormSchema.tsx b/packages/esm-admin-app/src/components/users/userManagementFormSchema.tsx index 9d22dc220..1631dc959 100644 --- a/packages/esm-admin-app/src/components/users/userManagementFormSchema.tsx +++ b/packages/esm-admin-app/src/components/users/userManagementFormSchema.tsx @@ -1,5 +1,5 @@ import { useTranslation } from 'react-i18next'; -import { z } from 'zod'; +import { optional, z } from 'zod'; const UserManagementFormSchema = () => { const { t } = useTranslation(); @@ -34,6 +34,28 @@ const UserManagementFormSchema = () => { primaryFacility: z.string().optional(), providerLicense: z.string().optional(), licenseExpiryDate: z.string().optional(), + permanent: z.boolean().optional(), + enabled: z.boolean().optional(), + stockOperation: z + .array( + z.object({ + operationTypeName: z.string().optional(), + operationTypeUuid: z.string().optional(), + }), + ) + .optional(), + operationLocation: z + .array( + z.object({ + locationName: z.string().optional(), + locationUuid: z.string().optional(), + }), + ) + .optional(), + + activeTo: z.string().optional(), + activeFrom: z.string().optional(), + isEditProvider: z.boolean().optional(), }); return { userManagementFormSchema }; diff --git a/packages/esm-admin-app/src/config-schema.ts b/packages/esm-admin-app/src/config-schema.ts index 19439bd48..b2f6e2961 100755 --- a/packages/esm-admin-app/src/config-schema.ts +++ b/packages/esm-admin-app/src/config-schema.ts @@ -1,4 +1,5 @@ -import { Type } from '@openmrs/esm-framework'; +import { fhirBaseUrl, Type } from '@openmrs/esm-framework'; +import dayjs from 'dayjs'; export const configSchema = {}; @@ -98,3 +99,72 @@ export interface ProviderLocation { retired: boolean; attributes?: Array; } + +// Stock roles +export interface OpenmrsData extends OpenmrsObject {} +export interface OpenmrsObject { + uuid?: string; +} +export type BaseOpenmrsObject = OpenmrsObject; +export interface BaseOpenmrsData extends BaseOpenmrsObject, OpenmrsData {} +export interface StockOperationType extends BaseOpenmrsData { + uuid: string; + name: string; + description: string; + operationType: string; + hasSource: boolean; + hasDestination: boolean; + stockOperationTypeLocationScopes: Array; +} + +export interface StockOperationTypeLocationScope { + uuid: string; + locationTag: string; + isSource: string; + isDestination: string; +} + +// Pagging +export interface PageableResult { + results: ResultType[]; + totalCount: number | null; +} + +export interface PagingCriteria { + startIndex?: number | null; + limit?: number | null; +} + +// stock location + +export interface FHIRResponse { + entry: Array<{ resource: fhir.Location }>; + total: number; + type: string; + resourceType: string; +} + +export interface UserRoleScopeLocation extends BaseOpenmrsData { + locationUuid?: string; + locationName?: string; + enableDescendants?: boolean; +} + +export interface UserRoleScopeOperationType extends BaseOpenmrsData { + operationTypeUuid?: string; + operationTypeName?: string; +} + +export interface UserRoleScope extends BaseOpenmrsData { + userUuid?: string; + role?: string; + userName?: string; + userGivenName?: string; + userFamilyName?: string; + permanent: boolean; + activeFrom?: string; + activeTo?: string; + enabled: boolean; + locations?: Array; + operationTypes?: Array; +} diff --git a/packages/esm-admin-app/src/constants.ts b/packages/esm-admin-app/src/constants.ts index 1a8f630a1..7d54b0150 100644 --- a/packages/esm-admin-app/src/constants.ts +++ b/packages/esm-admin-app/src/constants.ts @@ -1,2 +1,23 @@ +import dayjs from 'dayjs'; + export const moduleName = '@kenyaemr/esm-admin-app'; export const etlBasePath = `${window.spaBase}`; + +export const today = () => { + const date = new Date(); + return new Date(date.getFullYear(), date.getMonth(), date.getDate()); +}; + +export const DATE_PICKER_CONTROL_FORMAT = 'd/m/Y'; + +// to move to a location + +export const DATE_PICKER_FORMAT = 'DD/MM/YYYY'; + +export const formatForDatePicker = (date: Date | null | undefined) => { + return formatDisplayDate(date, DATE_PICKER_FORMAT); +}; + +export const formatDisplayDate = (date: Date | null | undefined, format?: string) => { + return date ? dayjs(date).format(format ?? 'DD-MMM-YYYY') : ''; +}; diff --git a/packages/esm-admin-app/src/index.ts b/packages/esm-admin-app/src/index.ts index 1e9d0f109..1d1c87fd7 100755 --- a/packages/esm-admin-app/src/index.ts +++ b/packages/esm-admin-app/src/index.ts @@ -31,3 +31,7 @@ export const etlAdministrationLeftPannelLink = getSyncLifecycle( createLeftPanelLink({ title: 'ETL Administration', name: 'etl-administration' }), options, ); +export const facilitySetupLeftPanelLink = getSyncLifecycle( + createLeftPanelLink({ title: 'Facility Setup', name: 'facility-setup' }), + options, +); diff --git a/packages/esm-admin-app/src/root.component.tsx b/packages/esm-admin-app/src/root.component.tsx index 7c84769d4..8ba92fa9c 100755 --- a/packages/esm-admin-app/src/root.component.tsx +++ b/packages/esm-admin-app/src/root.component.tsx @@ -5,6 +5,7 @@ import styles from './root.scss'; import LeftPanel from './components/side-menu/left-pannel.component'; import UserManagentLandingPage from './components/users/manage-users/manage-user.component'; import EtlAdminDashboard from './components/dashboard/etl-dashboard.component'; +import FacilitySetup from './components/facility-setup/facility-setup.component'; const Root: React.FC = () => { const spaBasePath = window.spaBase; @@ -26,6 +27,7 @@ const Root: React.FC = () => { } /> } /> } /> + } /> diff --git a/packages/esm-admin-app/src/routes.json b/packages/esm-admin-app/src/routes.json index ac04a8b03..64b48e9a0 100755 --- a/packages/esm-admin-app/src/routes.json +++ b/packages/esm-admin-app/src/routes.json @@ -18,6 +18,11 @@ "component": "etlAdministrationLeftPannelLink", "name": "etl-administration-left-panel-link", "slot": "admin-left-panel-slot" + }, + { + "component": "facilitySetupLeftPanelLink", + "name": "facility-setup-left-panel-link", + "slot": "admin-left-panel-slot" } ], "workspaces": [ diff --git a/packages/esm-admin-app/src/types/index.ts b/packages/esm-admin-app/src/types/index.ts index ac81cd6dd..8d3be6898 100644 --- a/packages/esm-admin-app/src/types/index.ts +++ b/packages/esm-admin-app/src/types/index.ts @@ -10,3 +10,27 @@ export interface DashboardConfig { slot: string; title: string; } +export interface FrontendModule { + name: string; + version?: string; +} +export interface DefaultFacility { + locationId: number; + uuid: string; + display: string; + operationalStatus: string; + shaContracted: string; + shaFacilityExpiryDate: string; +} + +export interface FacilityData { + shaKephLevel?: string; + mflCode?: string; + display?: string; + operationalStatus?: string; + shaContracted?: string; + shaFacilityId?: string; + shaFacilityLicenseNumber?: string; + shaFacilityExpiryDate?: string; + source?: string; +} diff --git a/packages/esm-admin-app/src/user-management.resources.ts b/packages/esm-admin-app/src/user-management.resources.ts index fbe11839d..9bcb3c0e0 100644 --- a/packages/esm-admin-app/src/user-management.resources.ts +++ b/packages/esm-admin-app/src/user-management.resources.ts @@ -1,6 +1,19 @@ -import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; +import { fhirBaseUrl, openmrsFetch, restBaseUrl } from '@openmrs/esm-framework'; import useSWR, { mutate } from 'swr'; -import { AttributeType, Provider, ProviderAttributes, ProviderLocation, Role, User } from './config-schema'; +import { + AttributeType, + FHIRResponse, + PageableResult, + Provider, + ProviderAttributes, + ProviderLocation, + Role, + StockOperationType, + User, + UserRoleScope, +} from './config-schema'; +import uniqBy from 'lodash-es/uniqBy'; +import { useMemo } from 'react'; export const useUser = () => { const url = `${restBaseUrl}/user?v=custom:(uuid,username,display,systemId,retired,person:(uuid,display,gender,names:(givenName,familyName,middleName),attributes:(uuid,display)),roles:(uuid,description,display,name))`; @@ -48,25 +61,29 @@ export const createProvider = async ( }); }; -export const createUser = async ( - user: Partial, - setProvider: boolean, - attributes: Partial, - uuid?: string, - providerUUID?: string, -) => { - const url = uuid ? `${restBaseUrl}/user/${uuid}` : `${restBaseUrl}/user`; +export const createUser = async (user: Partial, uuid?: string) => { + const userUrl = uuid ? `${restBaseUrl}/user/${uuid}` : `${restBaseUrl}/user`; - const response = await postUser(user, url); + return await postUser(user, userUrl); +}; - if (setProvider || (response.person && response.person.uuid)) { - const personUUID = response.person.uuid; - const identifier = response.systemId; - const providerUrl = providerUUID ? `${restBaseUrl}/provider/${providerUUID}` : `${restBaseUrl}/provider`; - return await createProvider(personUUID, identifier, attributes, providerUrl); - } +export const createOrUpdateUserRoleScope = async ( + userRoleScopeUrl?: string, + userRoleScopePayload?: Partial, + userUuid?: string, +) => { + const userRoleScopeBody = { + userUuid: userUuid, + ...userRoleScopePayload, + }; - return response; + return await openmrsFetch(userRoleScopeUrl, { + method: 'POST', + body: JSON.stringify(userRoleScopeBody), + headers: { + 'Content-Type': 'application/json', + }, + }); }; export const handleMutation = (url: string) => { @@ -133,3 +150,33 @@ export const useLocation = () => { locationError: error, }; }; + +// getStockOperationTypes +export function useStockOperationTypes() { + const apiUrl = `${restBaseUrl}/stockmanagement/stockoperationtype?v=default`; + const { data, isLoading, error } = useSWR< + { + data: PageableResult; + }, + Error + >(apiUrl, openmrsFetch); + return { + types: data?.data || >{}, + loadingStock: isLoading, + error, + }; +} + +export function useStockTagLocations() { + const apiUrl = `${fhirBaseUrl}/Location?_summary=data&_tag=main store,main pharmacy,dispensary `; + const { data, error, isLoading } = useSWR<{ data: FHIRResponse }>(apiUrl, openmrsFetch); + const stockLocations = useMemo( + () => data?.data?.entry?.map((response) => response.resource) ?? [], + [data?.data?.entry], + ); + return { + stockLocations: uniqBy(stockLocations, 'id') ?? [], + isLoading, + error, + }; +} diff --git a/packages/esm-admin-app/translations/en.json b/packages/esm-admin-app/translations/en.json index 67db1700e..5352f9795 100644 --- a/packages/esm-admin-app/translations/en.json +++ b/packages/esm-admin-app/translations/en.json @@ -10,8 +10,8 @@ "endTime": "End time", "etlAdministration": "ETL Admin", "etlOperation": "ETL operations", - "etlOperationLog": "ETL Operations Log", "etlsOperationsLoading": "Please wait {{currentOperation}} is in progress...", + "facilityInfo": "Facility Info", "familyName": "Family Name", "given": "Given", "home": "Home", @@ -35,6 +35,10 @@ "searchLabel": "Search", "searchUser": "Search user table", "startTime": "Start time", + "synchronizeWithHie": "Synchronize with HIE", + "synchronizingFacilityData": "Please wait, Synchronizing Info.", + "syncingHieError": "Syncing with HIE Failed", + "syncingHieSuccess": "Synchronization Complete", "systemId": "System ID", "userManagement": "User Management", "username": "Username", diff --git a/packages/esm-billing-app/package.json b/packages/esm-billing-app/package.json index e2c2ce359..29084f7e1 100644 --- a/packages/esm-billing-app/package.json +++ b/packages/esm-billing-app/package.json @@ -37,11 +37,11 @@ "url": "https://github.com/palladiumkenya/kenyaemr-esm-core/issues" }, "dependencies": { - "@carbon/react": "^1.72.0", "lodash-es": "^4.17.15", "react-to-print": "^2.14.13" }, "peerDependencies": { + "@carbon/react": "1.x", "@openmrs/esm-framework": "5.x", "react": "^18.1.0", "react-i18next": "11.x", diff --git a/packages/esm-billing-app/src/benefits-package/benefits-package.mock.ts b/packages/esm-billing-app/src/benefits-package/benefits-package.mock.ts index a1c59b684..15e7cc376 100644 --- a/packages/esm-billing-app/src/benefits-package/benefits-package.mock.ts +++ b/packages/esm-billing-app/src/benefits-package/benefits-package.mock.ts @@ -4,7 +4,7 @@ import { Diagnosis, Package, PatientBenefit, - SHAIntervension, + SHAIntervention, shifIdentifiersResponse, } from '../types'; @@ -52,10 +52,10 @@ export const packages = [ }, ] as Array; -export const intervensions = patientBenefits.map(({ interventionCode, interventionName }) => ({ +export const interventions = patientBenefits.map(({ interventionCode, interventionName }) => ({ interventionCode, interventionName, -})) as Array; +})) as Array; export const coverageEligibilityResponse = [ { diff --git a/packages/esm-billing-app/src/benefits-package/forms/benefit-pre-auth-form.workspace.tsx b/packages/esm-billing-app/src/benefits-package/forms/benefit-pre-auth-form.workspace.tsx index edf169c07..e03f3f6ad 100644 --- a/packages/esm-billing-app/src/benefits-package/forms/benefit-pre-auth-form.workspace.tsx +++ b/packages/esm-billing-app/src/benefits-package/forms/benefit-pre-auth-form.workspace.tsx @@ -28,7 +28,7 @@ import useProvider from '../../hooks/useProvider'; import { PatientBenefit } from '../../types'; import { preAuthenticateBenefit, preauthSchema } from '../benefits-package.resources'; import styles from './benefits-pre-auth-form.scss'; -import PackageIntervensions from './package-intervensions.component'; +import PackageInterventions from './package-interventions.component'; import { ErrorState } from '@openmrs/esm-patient-common-lib'; type BenefitsPreAuth = z.infer; @@ -240,8 +240,9 @@ const BenefitPreAuthForm: React.FC = ({ closeWorkspace, {selectedPackageObservable && ( - package_.uuid === selectedPackageObservable)?.packageCode ?? ''} + patientUuid={patientUuid} /> )} @@ -255,7 +256,7 @@ const BenefitPreAuthForm: React.FC = ({ closeWorkspace, invalid={form.formState.errors[field.name]?.message} invalidText={form.formState.errors[field.name]?.message} id="diagnoses" - titleText={t('diagnosis', 'Diagnosis')} + titleText={t('finalDiagnosis', 'Final Diagnosis')} selectedItems={field.value} label="Choose option" items={diagnoses.map((r) => r.id)} @@ -279,7 +280,7 @@ const BenefitPreAuthForm: React.FC = ({ closeWorkspace, - - - )} -
-
- - - {inforce ? t('active', 'Active') : t('inactive', 'Inactive')} - -
+ if (isRegisteredOnSHA) { + return ( + +
+
+ {t('insurer', 'Insurer:')}{' '} + SHA + {isActive && ( + + + + )} +
+
+ + + {isActive ? t('active', 'Active') : t('inactive', 'Inactive')} +
- ); - })} - - ); +
+ + ); + } }; export default SHANumberValidity; diff --git a/packages/esm-billing-app/src/claims/dashboard/form/claims-form.component.tsx b/packages/esm-billing-app/src/claims/dashboard/form/claims-form.component.tsx index 326f1a8cf..b8cbc38d3 100644 --- a/packages/esm-billing-app/src/claims/dashboard/form/claims-form.component.tsx +++ b/packages/esm-billing-app/src/claims/dashboard/form/claims-form.component.tsx @@ -21,7 +21,7 @@ import { Controller, FormProvider, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { useParams } from 'react-router-dom'; import { z } from 'zod'; -import PackageIntervensions from '../../../benefits-package/forms/package-intervensions.component'; +import PackageInterventions from '../../../benefits-package/forms/package-interventions.component'; import { formatDate } from '../../../helpers/functions'; import { useSystemSetting } from '../../../hooks/getMflCode'; import usePackages from '../../../hooks/usePackages'; @@ -314,8 +314,9 @@ const ClaimsForm: React.FC = ({ bill, selectedLineItems }) => { {selectedPackageObservable && ( - package_.uuid === selectedPackageObservable)?.packageCode ?? ''} + patientUuid={patientUuid} /> diff --git a/packages/esm-billing-app/src/claims/pre-auth/form/pre-auth-form.component.tsx b/packages/esm-billing-app/src/claims/pre-auth/form/pre-auth-form.component.tsx deleted file mode 100644 index 9b373c312..000000000 --- a/packages/esm-billing-app/src/claims/pre-auth/form/pre-auth-form.component.tsx +++ /dev/null @@ -1,364 +0,0 @@ -import React, { useEffect, useMemo, useState } from 'react'; -import { useTranslation } from 'react-i18next'; -import { - Column, - TextArea, - Form, - Layer, - Stack, - TextInput, - Row, - Button, - ButtonSet, - MultiSelect, - Tag, - InlineLoading, -} from '@carbon/react'; -import { navigate, showSnackbar } from '@openmrs/esm-framework'; -import { useSystemSetting } from '../../../hooks/getMflCode'; -import { useParams } from 'react-router-dom'; -import { useForm, Controller } from 'react-hook-form'; -import { z } from 'zod'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { useVisit } from '../../dashboard/form/claims-form.resource'; -import styles from './pre-auth-form.scss'; -import { LineItem, MappedBill } from '../../../types'; -import { useInterventions, usePackages } from './pre-auth-form.resource'; -import { Service } from '../../../../../esm-lab-manifest-app/src/metrics/lab-manifest-metrics.component'; - -type PreAuthFormProps = { - bill: MappedBill; - selectedLineItems: LineItem[]; -}; - -const PreAuthFormSchema = z.object({ - claimCode: z.string().nonempty({ message: 'Claim code is required' }), - guaranteeId: z.string().nonempty({ message: 'Guarantee Id is required' }), - preAuthJustification: z.string().nonempty({ message: 'Claim justification is required' }), - diagnoses: z - .array( - z.object({ - id: z.string(), - text: z.string(), - }), - ) - .nonempty({ message: 'At least one diagnosis is required' }), - visitType: z.string().nonempty({ message: 'Visit type is required' }), - facility: z.string().nonempty({ message: 'Facility is required' }), - packages: z.array(z.string()).nonempty({ message: 'At least one package is required' }), - interventions: z.array(z.string()).nonempty({ message: 'At least one intervention is required' }), -}); - -const PreAuthForm: React.FC = ({ bill, selectedLineItems }) => { - const { t } = useTranslation(); - const { mflCodeValue } = useSystemSetting('facility.mflcode'); - const { patientUuid, billUuid } = useParams(); - const { visits: recentVisit } = useVisit(patientUuid); - const { interventions } = useInterventions(); - const { packages } = usePackages(); - - const [loading, setLoading] = useState(false); - - const handleNavigateToBillingOptions = () => - navigate({ - to: window.getOpenmrsSpaBase() + `home/billing/patient/${patientUuid}/${billUuid}`, - }); - - const diagnoses = useMemo(() => { - return ( - recentVisit?.encounters?.flatMap( - (encounter) => - encounter.diagnoses.map((diagnosis) => ({ - id: diagnosis.diagnosis.coded.uuid, - text: diagnosis.display, - certainty: diagnosis.certainty, - })) || [], - ) || [] - ); - }, [recentVisit]); - - const confirmedDiagnoses = useMemo(() => { - return diagnoses.filter((diagnosis) => diagnosis.certainty === 'CONFIRMED'); - }, [diagnoses]); - - const { - control, - handleSubmit, - formState: { errors, isValid }, - setValue, - reset, - } = useForm({ - mode: 'all', - resolver: zodResolver(PreAuthFormSchema), - defaultValues: { - claimCode: '', - guaranteeId: '', - preAuthJustification: '', - diagnoses: [], - visitType: '', - facility: '', - packages: [], - interventions: [], - }, - }); - - const onSubmit = async (data) => { - setLoading(true); - try { - showSnackbar({ - kind: 'success', - title: t('requestPreAuth', 'Pre Authorization'), - subtitle: t('sendClaim', 'Pre authorization request sent successfully'), - timeoutInMs: 3000, - isLowContrast: true, - }); - reset(); - setTimeout(() => { - navigate({ - to: window.getOpenmrsSpaBase() + `home/billing/`, - }); - }, 2000); - } catch (err) { - console.error(err); - showSnackbar({ - kind: 'error', - title: t('requestPreAuthError', 'Pre Authorization Error'), - subtitle: t('sendClaimError', 'Pre authorization request failed, please try later'), - timeoutInMs: 2500, - isLowContrast: true, - }); - } finally { - setLoading(false); - } - }; - - useEffect(() => { - reset({ - diagnoses: confirmedDiagnoses, - visitType: recentVisit?.visitType?.display || '', - facility: `${recentVisit?.location?.display || ''} - ${mflCodeValue || ''}`, - claimCode: '', - guaranteeId: '', - preAuthJustification: '', - packages: [], - interventions: [], - }); - }, [confirmedDiagnoses, recentVisit, mflCodeValue, reset]); - - return ( -
- - {t('formTitle', 'Fill in the form details')} - - - ( -