import React, { useCallback, useMemo, useState } from 'react'; import { Button, Column, InlineLoading, RadioButton, RadioButtonGroup, Stack } from '@carbon/react'; import { ArrowLeft, ArrowRight, Departure, ListChecked, Save, SendFilled } from '@carbon/react/icons'; import { useFormContext } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import { restBaseUrl, showSnackbar } from '@openmrs/esm-framework'; import { createStockOperation, deleteStockOperationItem, updateStockOperation } from '../../stock-operations.resource'; import { extractErrorMessagesFromResponse } from '../../../constants'; import { handleMutate } from '../../../utils'; import { OperationType, type StockOperationType } from '../../../core/api/types/stockOperation/StockOperationType'; import { otherUser } from '../../../core/utils/utils'; import { launchStockOperationsModal } from '../../stock-operation.utils'; import { type StockOperationDTO } from '../../../core/api/types/stockOperation/StockOperationDTO'; import { type StockOperationItemDTO } from '../../../core/api/types/stockOperation/StockOperationItemDTO'; import { type StockOperationItemDtoSchema } from '../../validation-schema'; import useOperationTypePermisions from '../hooks/useOperationTypePermisions'; import styles from '../stock-operation-form.scss'; type StockOperationSubmissionFormStepProps = { onPrevious?: () => void; stockOperation?: StockOperationDTO; stockOperationType: StockOperationType; onNext?: () => void; dismissWorkspace?: () => void; }; const StockOperationSubmissionFormStep: React.FC = ({ onPrevious, stockOperationType, stockOperation, onNext, dismissWorkspace, }) => { const { t } = useTranslation(); const operationTypePermision = useOperationTypePermisions(stockOperationType); const editable = useMemo(() => !stockOperation || stockOperation.status === 'NEW', [stockOperation]); const form = useFormContext(); const [approvalRequired, setApprovalRequired] = useState(stockOperation?.approvalRequired); const isStockIssueOperation = useMemo( () => OperationType.STOCK_ISSUE_OPERATION_TYPE === stockOperationType.operationType, [stockOperationType], ); const handleRadioButtonChange = (selectedItem: boolean) => { setApprovalRequired(selectedItem); }; const handleSave = useCallback(async () => { let result: StockOperationDTO; // To store the result for returning await form.handleSubmit(async (formData) => { try { // Get deleted items (items in stock operation bt not i form data) const itemsToDelete = stockOperation?.stockOperationItems?.reduce>((prev, curr) => { const itemDoNotExistInFormData = formData.stockOperationItems.findIndex((item) => item.uuid === curr.uuid) === -1; if (itemDoNotExistInFormData) { return [...prev, curr]; } return prev; }, []) ?? []; // Delete them from backend asynchronosely const deleted = await Promise.allSettled(itemsToDelete.map((item) => deleteStockOperationItem(item.uuid))); // Give delete status on completion deleted.forEach((del, index) => { showSnackbar({ kind: del.status === 'rejected' ? 'error' : 'success', title: del.status === 'rejected' ? t('stockOperationItemDeleteError', 'Error deleting stock operation item {{item}}', { item: itemsToDelete[index].commonName, }) : t('success', 'Success'), subtitle: del.status === 'rejected' ? del.reason?.message : t('stockOperationItemDeleteSuccess', 'Stock operation item {{item}} deleted successfully', { item: itemsToDelete[index].commonName, }), }); }); // construct update payload const payload = { ...formData, // Remove other uuid if responsible person is set to other responsiblePersonUuid: formData.responsiblePersonUuid === otherUser.uuid ? undefined : formData.responsiblePersonUuid, approvalRequired: approvalRequired ? true : false, stockOperationItems: [ ...formData.stockOperationItems.map((item) => ({ ...item, uuid: item.uuid.startsWith('new-item-') || (!stockOperation && isStockIssueOperation) ? undefined : item.uuid, // Remove uuid for newly inserted items and stock issue items derived from requisition to avoid foreign key constraint lookup error })), ], }; const resp = await (stockOperation ? updateStockOperation(stockOperation, payload as any) : createStockOperation(payload as any)); result = resp.data; // Store the response data handleMutate(`${restBaseUrl}/stockmanagement/stockoperation`); dismissWorkspace?.(); showSnackbar({ isLowContrast: true, title: stockOperation ? t('editStockOperation', 'Edit stock operation') : t('addStockOperation', 'Add stock operation'), kind: 'success', subtitle: stockOperation ? t('stockOperationEdited', 'Stock operation edited successfully') : t('stockOperationAdded', 'Stock operation added successfully'), }); } catch (error) { const errorMessages = extractErrorMessagesFromResponse(error); showSnackbar({ subtitle: errorMessages.join(', '), title: t('errorSavingForm', 'Error on saving form'), kind: 'error', isLowContrast: true, }); throw error; } })(); // Call handleSubmit to trigger validation and submission return result; // Return the result after handleSubmit completes }, [form, stockOperation, t, approvalRequired, isStockIssueOperation, dismissWorkspace]); const handleComplete = useCallback(() => { handleSave().then((operation) => { launchStockOperationsModal('Complete', false, { ...operation, status: 'COMPLETED' }); }); }, [handleSave]); const handleSubmitForReview = useCallback(() => { handleSave().then((operation) => { launchStockOperationsModal('Submit', false, { ...operation, status: 'SUBMITTED' }); }); }, [handleSave]); const handleDispatch = useCallback(() => { handleSave().then((operation) => { launchStockOperationsModal('Dispatch', false, { ...operation, status: 'DISPATCHED' }); }); }, [handleSave]); return (

{operationTypePermision?.requiresDispatchAcknowledgement ? t('submitAndDispatch', 'Submit/Dispatch') : t('submitAndComplete', 'Submit/Complete')}

handleRadioButtonChange(value === 'true')} readOnly={!editable} valueSelected={approvalRequired === true ? 'true' : approvalRequired === false ? 'false' : null} > {editable && ( {approvalRequired != null && ( <> {!operationTypePermision.requiresDispatchAcknowledgement && !approvalRequired && ( )} {operationTypePermision.requiresDispatchAcknowledgement && !approvalRequired && ( )} {approvalRequired && ( )} )} )}
{typeof onNext === 'function' && ( )} {typeof onPrevious === 'function' && (
); }; export default StockOperationSubmissionFormStep;