import React, { useCallback, useEffect, useState } from 'react'; import classNames from 'classnames'; import { useOrderBasket } from '@openmrs/esm-patient-common-lib'; import { translateFrom, useLayoutType, useSession, type DefaultWorkspaceProps, ExtensionSlot, launchWorkspace, } from '@openmrs/esm-framework'; import { careSettingUuid, prepImagingOrderPostData } from '../api'; import { Button, ButtonSet, Column, ComboBox, DatePicker, DatePickerInput, Form, Layer, Grid, InlineNotification, TextArea, } from '@carbon/react'; import { useTranslation } from 'react-i18next'; import { priorityOptions } from './imaging-order'; import { useImagingTypes } from './useImagingTypes'; import { Controller, type FieldErrors, useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { z } from 'zod'; import { moduleName } from '../../../constants'; import styles from './imaging-order-form.scss'; import type { ImagingOrderBasketItem } from '../../../types'; export interface ImagingOrderFormProps { initialOrder: ImagingOrderBasketItem; closeWorkspace: DefaultWorkspaceProps['closeWorkspace']; closeWorkspaceWithSavedChanges: DefaultWorkspaceProps['closeWorkspaceWithSavedChanges']; promptBeforeClosing: DefaultWorkspaceProps['promptBeforeClosing']; } // Designs: // https://app.zeplin.io/project/60d5947dd636aebbd63dce4c/screen/640b06c440ee3f7af8747620 // https://app.zeplin.io/project/60d5947dd636aebbd63dce4c/screen/640b06d286e0aa7b0316db4a export function ImagingOrderForm({ initialOrder, closeWorkspace, closeWorkspaceWithSavedChanges, promptBeforeClosing, }: ImagingOrderFormProps) { const { t } = useTranslation(); const isTablet = useLayoutType() === 'tablet'; const session = useSession(); const { orders, setOrders } = useOrderBasket('imaging', prepImagingOrderPostData); const { testTypes, isLoading: isLoadingTestTypes, error: errorLoadingTestTypes } = useImagingTypes(); const [showErrorNotification, setShowErrorNotification] = useState(false); const lateralityItems = [ { value: 'LEFT', label: 'Left' }, { value: 'RIGHT', label: 'Right' }, { value: 'BILATERAL', label: 'Bilateral' }, ]; const imagingOrderFormSchema = z.object({ instructions: z.string().optional(), urgency: z.string().refine((value) => value !== '', { message: translateFrom(moduleName, 'addLabOrderPriorityRequired', 'Priority is required'), }), testType: z.object( { label: z.string(), conceptUuid: z.string() }, { required_error: translateFrom(moduleName, 'addLabOrderLabTestTypeRequired', 'Test type is required'), invalid_type_error: translateFrom(moduleName, 'addLabOrderLabReferenceRequired', 'Test type is required'), }, ), scheduleDate: z.union([z.string(), z.date(), z.string().optional()]), commentsToFulfiller: z.string().optional(), laterality: z.string().optional(), orderReasonNonCoded: z.string().min(1, { message: translateFrom(moduleName, 'addOrderReasonRequired', 'Order reason is required'), }), }); const { control, handleSubmit, formState: { errors, defaultValues, isDirty }, } = useForm({ mode: 'all', resolver: zodResolver(imagingOrderFormSchema), defaultValues: { ...initialOrder, }, }); const handleFormSubmission = useCallback( (data: ImagingOrderBasketItem) => { data.action = 'NEW'; data.careSetting = careSettingUuid; data.orderer = session.currentProvider.uuid; const newOrders = [...orders]; const existingOrder = orders.find((order) => order.testType.conceptUuid == defaultValues.testType.conceptUuid); const orderIndex = existingOrder ? orders.indexOf(existingOrder) : orders.length; newOrders[orderIndex] = data; setOrders(newOrders); closeWorkspaceWithSavedChanges({ onWorkspaceClose: () => launchWorkspace('order-basket'), }); }, [orders, setOrders, defaultValues, closeWorkspaceWithSavedChanges, session], ); const cancelOrder = useCallback(() => { setOrders(orders.filter((order) => order.testType.conceptUuid !== defaultValues.testType.conceptUuid)); closeWorkspace({ onWorkspaceClose: () => launchWorkspace('order-basket'), }); }, [closeWorkspace, orders, setOrders, defaultValues]); const onError = (errors: FieldErrors) => { if (errors) { setShowErrorNotification(true); } }; useEffect(() => { promptBeforeClosing(() => isDirty); }, [isDirty, promptBeforeClosing]); const [showScheduleDate, setShowScheduleDate] = useState(false); return ( <> {errorLoadingTestTypes && ( )}
( onChange(selectedItem)} invalid={errors.testType?.message} invalidText={errors.testType?.message} /> )} /> ( option.value === value) || null} items={priorityOptions} onBlur={onBlur} onChange={({ selectedItem }) => { onChange(selectedItem?.value || ''); setShowScheduleDate(selectedItem?.label === 'Scheduled'); }} invalid={errors.urgency?.message} invalidText={errors.urgency?.message} /> )} /> {showScheduleDate && (
( onChange(newStartDate)} onBlur={onBlur} ref={ref}> )} />
)} ( option.value === value) || null} items={lateralityItems} onBlur={onBlur} onChange={({ selectedItem }) => onChange(selectedItem?.value || '')} invalid={errors.laterality?.message} invalidText={errors.laterality?.message} itemToString={(item) => item?.label} /> )} /> (