From 1e0a637c4c28c0053ba0217f17575f1de085ff9c Mon Sep 17 00:00:00 2001 From: Munyua123 Date: Wed, 18 Dec 2024 08:37:37 +0300 Subject: [PATCH 1/2] (feat) SJT-132 Create the Edit Payment mode modal --- packages/esm-billing-app/package.json | 4 +- packages/esm-billing-app/src/index.ts | 2 + .../payment-modes/edit-payment-mode.modal.tsx | 163 ++++++++++++++++++ .../payment-mode-dashboard.component.tsx | 14 +- packages/esm-billing-app/src/routes.json | 12 +- 5 files changed, 183 insertions(+), 12 deletions(-) create mode 100644 packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx diff --git a/packages/esm-billing-app/package.json b/packages/esm-billing-app/package.json index af66d5c..717f8af 100644 --- a/packages/esm-billing-app/package.json +++ b/packages/esm-billing-app/package.json @@ -1,6 +1,6 @@ { "name": "@ehospital/esm-billing-app", - "version": "1.2.8", + "version": "1.2.9", "description": "Billing frontend module for use in O3", "browser": "dist/ehospital-esm-billing-app.js", "main": "src/index.ts", @@ -121,5 +121,5 @@ "*.{js,jsx,ts,tsx}": "eslint --cache --fix" }, "packageManager": "yarn@4.1.1", - "gitHead": "7c7b1efa438601ea3b1f2697a6c96c57b46f9b9c" + "gitHead": "2b7c7512b5292f14f4181c835a942e3e278fb303" } diff --git a/packages/esm-billing-app/src/index.ts b/packages/esm-billing-app/src/index.ts index 7359957..2be6ce3 100644 --- a/packages/esm-billing-app/src/index.ts +++ b/packages/esm-billing-app/src/index.ts @@ -27,6 +27,7 @@ import { ClockIn } from './payment-points/payment-point/clock-in.component'; import { ClockOut } from './payment-points/payment-point/clock-out.component'; import DeletePaymentModeModal from './payment-modes/delete-payment-mode.modal'; import PaymentModeWorkspace from "./payment-modes/payment-mode.workspace"; +import EditPaymentMode from './payment-modes/edit-payment-mode.modal'; const moduleName = '@ehospital/esm-billing-app'; @@ -83,6 +84,7 @@ export const paymentModesPanelLink = getSyncLifecycle( export const paymentModeWorkspace = getSyncLifecycle(PaymentModeWorkspace, options); export const deletePaymentModeModal = getSyncLifecycle(DeletePaymentModeModal, options); +export const editPaymentMode = getSyncLifecycle(EditPaymentMode, options) export const importTranslation = require.context('../translations', false, /.json$/, 'lazy'); diff --git a/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx b/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx new file mode 100644 index 0000000..5de8ee5 --- /dev/null +++ b/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx @@ -0,0 +1,163 @@ +import React, { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Button, Form, Loading, ModalBody, ModalFooter, ModalHeader, TextInput } from '@carbon/react'; +import { restBaseUrl, showSnackbar, useLayoutType } from '@openmrs/esm-framework'; +import { Controller, useForm } from 'react-hook-form'; +import styles from './payment-mode.workspace.scss'; +import { z } from 'zod'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { createPaymentMode, handleMutation } from './payment-mode.resource'; +import { PaymentMode } from '../types'; +import usePaymentModeFormSchema from './usePaymentModeFormSchema'; +import PaymentModeAttributeFields from './payment-attributes/payment-mode-attributes.component'; +import { Add } from '@carbon/react/icons'; + +type EditPaymentModeModalProps = { + closeModal: () => void; + initialPaymentMode?: PaymentMode; + }; + +const EditPaymentMode : React.FC = ({ closeModal, initialPaymentMode = {} as PaymentMode, }) => { + const { t } = useTranslation(); + const { paymentModeFormSchema } = usePaymentModeFormSchema(); + type PaymentModeFormSchema = z.infer; + const formDefaultValues = Object.keys(initialPaymentMode).length > 0 ? initialPaymentMode : {}; + + const formMethods = useForm({ + resolver: zodResolver(paymentModeFormSchema), + mode: 'all', + defaultValues: formDefaultValues, + }); + + const { errors, isSubmitting } = formMethods.formState; + + // field array + // const { + // fields: attributeTypeFields, + // append: appendAttributeType, + // remove: removeAttributeType, + // } = useFieldArray({ + // control: formMethods.control, + // name: 'attributeTypes', + // }); + + // const mappedAttributeTypes = (attributes) => { + // return { + // name: attributes.name, + // description: attributes.description, + // retired: attributes.retired, + // attributeOrder: attributes?.attributeOrder ?? 0, + // format: attributes?.format ?? '', + // foreignKey: attributes?.foreignKey ?? null, + // regExp: attributes?.regExp ?? '', + // required: attributes.required, + // }; + // }; + + const onSubmit = async (data: PaymentModeFormSchema) => { + const payload: Partial = { + name: data.name, + description: data.description, + }; + + try { + const response = await createPaymentMode(payload, initialPaymentMode?.uuid ?? ''); + if (response.ok) { + showSnackbar({ + title: t('paymentModeUpdated', 'Payment mode updated successfully'), + subtitle: t('paymentModeUpdatedSubtitle', 'The payment mode has been updated successfully'), + kind: 'success', + isLowContrast: true, + }); + closeModal(); + handleMutation(`${restBaseUrl}/billing/paymentMode?v=full`); + } + } catch (error) { + const errorObject = error?.responseBody?.error; + const errorMessage = errorObject?.message ?? 'An error occurred while creating the payment mode'; + showSnackbar({ + title: t('paymentModeUpdateFailed', 'Payment mode updating failed'), + subtitle: t( + 'paymentModeCreationFailedSubtitle', + 'An error occurred while updating the payment mode {{errorMessage}}', + { errorMessage }, + ), + kind: 'error', + isLowContrast: true, + }); + } + }; + + const handleError = (error) => { + showSnackbar({ + title: t('paymentModeUpdateFailed', 'Payment mode updating failed'), + subtitle: t( + 'paymentModeCreationFailedSubtitle', + 'An error occurred while updating the payment mode {{errorMessage}}', + { errorMessage: JSON.stringify(error, null, 2) }, + ), + kind: 'error', + isLowContrast: true, + }); + }; + + return ( +
+ Edit Payment Mode + + ( + + )} + /> + ( + + )} + /> + + + + + +
+ ); +}; + +export default EditPaymentMode; diff --git a/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx b/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx index 0287b66..faaa7b2 100644 --- a/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx +++ b/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx @@ -55,6 +55,13 @@ const PaymentModeDashboard: React.FC = () => { }); }; + const showEditPaymentModeModal = (paymentMode: PaymentMode) => { + const dispose = showModal('edit-payment-mode', { + closeModal: () => dispose(), + initialPaymentMode: paymentMode, + }); + }; + const createPaymentModeModal = () => { const dispose = showModal('create-payment-mode', { closeModal: () => dispose(), @@ -160,12 +167,7 @@ const PaymentModeDashboard: React.FC = () => { - launchWorkspace('payment-mode-workspace', { - workspaceTitle: t('editPaymentMode', 'Edit Payment Mode'), - initialPaymentMode: paymentModes[index], - }) - } + onClick={() => showEditPaymentModeModal(paymentModes[index]) } itemText={t('edit', 'Edit')} /> Date: Wed, 18 Dec 2024 09:30:16 +0300 Subject: [PATCH 2/2] (fix) SJT-132 Create the Edit Payment mode modal --- packages/esm-billing-app/package.json | 4 +- packages/esm-billing-app/src/index.ts | 2 - .../payment-modes/edit-payment-mode.modal.tsx | 163 ------------------ .../payment-mode-dashboard.component.tsx | 20 +-- .../payment-mode.workspace.test.tsx | 9 +- .../payment-modes/payment-mode.workspace.tsx | 18 +- packages/esm-billing-app/src/routes.json | 4 - 7 files changed, 28 insertions(+), 192 deletions(-) delete mode 100644 packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx diff --git a/packages/esm-billing-app/package.json b/packages/esm-billing-app/package.json index 717f8af..b807903 100644 --- a/packages/esm-billing-app/package.json +++ b/packages/esm-billing-app/package.json @@ -1,6 +1,6 @@ { "name": "@ehospital/esm-billing-app", - "version": "1.2.9", + "version": "1.3.0", "description": "Billing frontend module for use in O3", "browser": "dist/ehospital-esm-billing-app.js", "main": "src/index.ts", @@ -121,5 +121,5 @@ "*.{js,jsx,ts,tsx}": "eslint --cache --fix" }, "packageManager": "yarn@4.1.1", - "gitHead": "2b7c7512b5292f14f4181c835a942e3e278fb303" + "gitHead": "309055b8757f9eca2383037d81b0b3a25c8a185d" } diff --git a/packages/esm-billing-app/src/index.ts b/packages/esm-billing-app/src/index.ts index 2be6ce3..7359957 100644 --- a/packages/esm-billing-app/src/index.ts +++ b/packages/esm-billing-app/src/index.ts @@ -27,7 +27,6 @@ import { ClockIn } from './payment-points/payment-point/clock-in.component'; import { ClockOut } from './payment-points/payment-point/clock-out.component'; import DeletePaymentModeModal from './payment-modes/delete-payment-mode.modal'; import PaymentModeWorkspace from "./payment-modes/payment-mode.workspace"; -import EditPaymentMode from './payment-modes/edit-payment-mode.modal'; const moduleName = '@ehospital/esm-billing-app'; @@ -84,7 +83,6 @@ export const paymentModesPanelLink = getSyncLifecycle( export const paymentModeWorkspace = getSyncLifecycle(PaymentModeWorkspace, options); export const deletePaymentModeModal = getSyncLifecycle(DeletePaymentModeModal, options); -export const editPaymentMode = getSyncLifecycle(EditPaymentMode, options) export const importTranslation = require.context('../translations', false, /.json$/, 'lazy'); diff --git a/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx b/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx deleted file mode 100644 index 5de8ee5..0000000 --- a/packages/esm-billing-app/src/payment-modes/edit-payment-mode.modal.tsx +++ /dev/null @@ -1,163 +0,0 @@ -import React, { useEffect } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Button, Form, Loading, ModalBody, ModalFooter, ModalHeader, TextInput } from '@carbon/react'; -import { restBaseUrl, showSnackbar, useLayoutType } from '@openmrs/esm-framework'; -import { Controller, useForm } from 'react-hook-form'; -import styles from './payment-mode.workspace.scss'; -import { z } from 'zod'; -import { zodResolver } from '@hookform/resolvers/zod'; -import { createPaymentMode, handleMutation } from './payment-mode.resource'; -import { PaymentMode } from '../types'; -import usePaymentModeFormSchema from './usePaymentModeFormSchema'; -import PaymentModeAttributeFields from './payment-attributes/payment-mode-attributes.component'; -import { Add } from '@carbon/react/icons'; - -type EditPaymentModeModalProps = { - closeModal: () => void; - initialPaymentMode?: PaymentMode; - }; - -const EditPaymentMode : React.FC = ({ closeModal, initialPaymentMode = {} as PaymentMode, }) => { - const { t } = useTranslation(); - const { paymentModeFormSchema } = usePaymentModeFormSchema(); - type PaymentModeFormSchema = z.infer; - const formDefaultValues = Object.keys(initialPaymentMode).length > 0 ? initialPaymentMode : {}; - - const formMethods = useForm({ - resolver: zodResolver(paymentModeFormSchema), - mode: 'all', - defaultValues: formDefaultValues, - }); - - const { errors, isSubmitting } = formMethods.formState; - - // field array - // const { - // fields: attributeTypeFields, - // append: appendAttributeType, - // remove: removeAttributeType, - // } = useFieldArray({ - // control: formMethods.control, - // name: 'attributeTypes', - // }); - - // const mappedAttributeTypes = (attributes) => { - // return { - // name: attributes.name, - // description: attributes.description, - // retired: attributes.retired, - // attributeOrder: attributes?.attributeOrder ?? 0, - // format: attributes?.format ?? '', - // foreignKey: attributes?.foreignKey ?? null, - // regExp: attributes?.regExp ?? '', - // required: attributes.required, - // }; - // }; - - const onSubmit = async (data: PaymentModeFormSchema) => { - const payload: Partial = { - name: data.name, - description: data.description, - }; - - try { - const response = await createPaymentMode(payload, initialPaymentMode?.uuid ?? ''); - if (response.ok) { - showSnackbar({ - title: t('paymentModeUpdated', 'Payment mode updated successfully'), - subtitle: t('paymentModeUpdatedSubtitle', 'The payment mode has been updated successfully'), - kind: 'success', - isLowContrast: true, - }); - closeModal(); - handleMutation(`${restBaseUrl}/billing/paymentMode?v=full`); - } - } catch (error) { - const errorObject = error?.responseBody?.error; - const errorMessage = errorObject?.message ?? 'An error occurred while creating the payment mode'; - showSnackbar({ - title: t('paymentModeUpdateFailed', 'Payment mode updating failed'), - subtitle: t( - 'paymentModeCreationFailedSubtitle', - 'An error occurred while updating the payment mode {{errorMessage}}', - { errorMessage }, - ), - kind: 'error', - isLowContrast: true, - }); - } - }; - - const handleError = (error) => { - showSnackbar({ - title: t('paymentModeUpdateFailed', 'Payment mode updating failed'), - subtitle: t( - 'paymentModeCreationFailedSubtitle', - 'An error occurred while updating the payment mode {{errorMessage}}', - { errorMessage: JSON.stringify(error, null, 2) }, - ), - kind: 'error', - isLowContrast: true, - }); - }; - - return ( -
- Edit Payment Mode - - ( - - )} - /> - ( - - )} - /> - - - - - -
- ); -}; - -export default EditPaymentMode; diff --git a/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx b/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx index faaa7b2..c23e70d 100644 --- a/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx +++ b/packages/esm-billing-app/src/payment-modes/payment-mode-dashboard.component.tsx @@ -55,16 +55,11 @@ const PaymentModeDashboard: React.FC = () => { }); }; - const showEditPaymentModeModal = (paymentMode: PaymentMode) => { - const dispose = showModal('edit-payment-mode', { - closeModal: () => dispose(), - initialPaymentMode: paymentMode, - }); - }; - - const createPaymentModeModal = () => { + const createPaymentModeModal = (paymentMode: PaymentMode, modalTitle: string) => { const dispose = showModal('create-payment-mode', { closeModal: () => dispose(), + initialPaymentMode: paymentMode, + modalTitle, }); } @@ -119,10 +114,9 @@ const PaymentModeDashboard: React.FC = () => {
@@ -167,7 +161,7 @@ const PaymentModeDashboard: React.FC = () => { showEditPaymentModeModal(paymentModes[index]) } + onClick={() => createPaymentModeModal(paymentModes[index], t('editPaymentMode', 'Edit Payment Mode')) } itemText={t('edit', 'Edit')} /> { test('should validate and submit correct form payload', async () => { const user = userEvent.setup(); - render(); + const mockCloseModal = jest.fn(); + render(); const nameInput = screen.getByRole('textbox', { name: /Payment mode name/i }); const descriptionInput = screen.getByRole('textbox', { name: /Payment mode description/i }); const submitButton = screen.getByRole('button', { name: /Save & Close/i }); @@ -48,6 +49,7 @@ describe('PaymentModeWorkspace', () => { test('should show error message when submitting form fails', async () => { const user = userEvent.setup(); + const mockCloseModal = jest.fn() mockCreatePaymentMode.mockRejectedValue({ responseBody: { error: { @@ -55,7 +57,7 @@ describe('PaymentModeWorkspace', () => { }, }, }); - render(); + render(); const nameInput = screen.getByRole('textbox', { name: /Payment mode name/i }); const descriptionInput = screen.getByRole('textbox', { name: /Payment mode description/i }); const submitButton = screen.getByRole('button', { name: /Save & Close/i }); @@ -75,7 +77,8 @@ describe('PaymentModeWorkspace', () => { test('should submit payload with attributeTypes', async () => { const user = userEvent.setup(); - render(); + const mockCloseModal = jest.fn() + render(); // key in name, description and retired const nameInput = screen.getByRole('textbox', { name: /Payment mode name/i }); diff --git a/packages/esm-billing-app/src/payment-modes/payment-mode.workspace.tsx b/packages/esm-billing-app/src/payment-modes/payment-mode.workspace.tsx index 53f2440..ef042d4 100644 --- a/packages/esm-billing-app/src/payment-modes/payment-mode.workspace.tsx +++ b/packages/esm-billing-app/src/payment-modes/payment-mode.workspace.tsx @@ -12,14 +12,22 @@ import usePaymentModeFormSchema from './usePaymentModeFormSchema'; import PaymentModeAttributeFields from './payment-attributes/payment-mode-attributes.component'; import { Add } from '@carbon/react/icons'; -const CreatePaymentMode = ({ closeModal }) => { +type CreatePaymentModeModalProps = { + closeModal: () => void; + initialPaymentMode?: PaymentMode; + modalTitle: string + }; + +const CreatePaymentMode : React.FC = ({ closeModal, initialPaymentMode = {} as PaymentMode, modalTitle }) => { const { t } = useTranslation(); const { paymentModeFormSchema } = usePaymentModeFormSchema(); type PaymentModeFormSchema = z.infer; + const formDefaultValues = Object.keys(initialPaymentMode).length > 0 ? initialPaymentMode : {}; const formMethods = useForm({ resolver: zodResolver(paymentModeFormSchema), mode: 'all', + defaultValues: formDefaultValues, }); const { errors, isSubmitting } = formMethods.formState; @@ -54,7 +62,7 @@ const CreatePaymentMode = ({ closeModal }) => { }; try { - const response = await createPaymentMode(payload, ''); + const response = await createPaymentMode(payload, initialPaymentMode?.uuid ?? ''); if (response.ok) { showSnackbar({ title: t('paymentModeCreated', 'Payment mode created successfully'), @@ -96,7 +104,7 @@ const CreatePaymentMode = ({ closeModal }) => { return (
- Create Payment Mode + {modalTitle} { {isSubmitting ? ( <> - {t('creating', 'Creating')} + {t('submitting', 'Submitting...')} ) : ( - t('create', 'Create') + t('saveAndClose', 'Save & close') )} diff --git a/packages/esm-billing-app/src/routes.json b/packages/esm-billing-app/src/routes.json index 85f674c..9a81812 100644 --- a/packages/esm-billing-app/src/routes.json +++ b/packages/esm-billing-app/src/routes.json @@ -159,10 +159,6 @@ "name": "create-payment-mode", "component": "createPaymentMode" }, - { - "name": "edit-payment-mode", - "component": "editPaymentMode" - }, { "name": "delete-payment-mode-modal", "component": "deletePaymentModeModal"