Skip to content

Commit

Permalink
Final tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
denniskigen committed Dec 23, 2024
1 parent 7883543 commit f2724f9
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const MetricsHeader = () => {
menuAlignment="bottom-end"
onClick={navigateToQueueScreen}
size={isDesktop(layout) ? 'sm' : 'lg'}
tooltipAlignment="top-end">
tooltipAlignment="left">
<UserHasAccess privilege="Emr: View Legacy Interface">
<MenuItem
label={t('addNewService', 'Add new service')}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
import React from 'react';
import userEvent from '@testing-library/user-event';
import { render, screen } from '@testing-library/react';
import { useLayoutType } from '@openmrs/esm-framework';
import { showSnackbar, useLayoutType } from '@openmrs/esm-framework';
import { saveQueue } from './queue-service.resource';
import QueueServiceForm from './queue-service-form.workspace';

const defaultProps = {
closeWorkspace: jest.fn(),
promptBeforeClosing: jest.fn(),
closeWorkspaceWithSavedChanges: jest.fn(),
promptBeforeClosing: jest.fn(),
setTitle: jest.fn(),
};

const mockSaveQueue = jest.mocked(saveQueue);
const mockShowSnackbar = jest.mocked(showSnackbar);
const mockUseLayoutType = jest.mocked(useLayoutType);

jest.mock('./queue-service.resource', () => ({
Expand All @@ -37,31 +40,88 @@ describe('QueueServiceForm', () => {
mockUseLayoutType.mockReturnValue('tablet');
});

it('should display required error messages when form is submitted with missing fields', async () => {
it('renders validation errors when form is submitted with missing fields', async () => {
const user = userEvent.setup();

render(<QueueServiceForm {...defaultProps} />);

const submitButton = screen.getByText('Save');
await user.click(submitButton);
expect(screen.getByText('Queue name is required')).toBeInTheDocument();
const queueNameInput = screen.getByRole('textbox', { name: /queue name/i });
const serviceTypeSelect = screen.getByRole('combobox', { name: /select a service type/i });
const locationSelect = screen.getByRole('combobox', { name: /select a location/i });
const cancelButton = screen.getByRole('button', { name: /cancel/i });
const saveButton = screen.getByRole('button', { name: /save/i });
expect(cancelButton).toBeInTheDocument();
expect(saveButton).toBeInTheDocument();
expect(queueNameInput).toBeInTheDocument();
expect(queueNameInput).not.toBeInvalid();
expect(serviceTypeSelect).toBeInTheDocument();
expect(serviceTypeSelect).not.toBeInvalid();

await user.click(saveButton);
expect(queueNameInput).toBeInvalid();

await user.type(queueNameInput, 'Test Queue');
expect(queueNameInput).not.toBeInvalid();
expect(serviceTypeSelect).toBeInvalid();

await user.selectOptions(serviceTypeSelect, '6f017eb0-b035-4acd-b284-da45f5067502');
await user.selectOptions(locationSelect, '34567eb0-b035-4acd-b284-da45f5067502');
await user.click(saveButton);

expect(serviceTypeSelect).not.toBeInvalid();
expect(queueNameInput).not.toBeInvalid();
expect(locationSelect).not.toBeInvalid();
});

it('should submit the form when all fields are filled', async () => {
it('submits the form when all required fields are filled', async () => {
const user = userEvent.setup();
render(<QueueServiceForm {...defaultProps} />);

const queueNameInput = screen.getByRole('textbox', { name: /queue name/i });
const serviceTypeSelect = screen.getByRole('combobox', { name: /select a service type/i });
const locationSelect = screen.getByRole('combobox', { name: /select a location/i });
const saveButton = screen.getByRole('button', { name: /save/i });

await user.type(queueNameInput, 'Test Queue');
await user.selectOptions(serviceTypeSelect, '6f017eb0-b035-4acd-b284-da45f5067502');
await user.selectOptions(locationSelect, '34567eb0-b035-4acd-b284-da45f5067502');
await user.click(saveButton);

expect(mockSaveQueue).toHaveBeenCalledTimes(1);
expect(mockSaveQueue).toHaveBeenCalledWith(
'Test Queue',
'6f017eb0-b035-4acd-b284-da45f5067502',
'',
'34567eb0-b035-4acd-b284-da45f5067502',
);
expect(mockShowSnackbar).toHaveBeenCalledTimes(1);
expect(mockShowSnackbar).toHaveBeenCalledWith({
kind: 'success',
title: expect.stringMatching(/queue service created/i),
subtitle: expect.stringMatching(/queue service created successfully/i),
});
});

it('renders an error message when the queue service creation fails', async () => {
const user = userEvent.setup();
mockSaveQueue.mockRejectedValueOnce(new Error('Internal server error'));
render(<QueueServiceForm {...defaultProps} />);

const queueNameInput = screen.getByLabelText('Queue name');
const serviceSelect = screen.getByLabelText('Select a service type');
const locationSelect = screen.getByLabelText('Select a location');
const queueNameInput = screen.getByRole('textbox', { name: /queue name/i });
const serviceTypeSelect = screen.getByRole('combobox', { name: /select a service type/i });
const locationSelect = screen.getByRole('combobox', { name: /select a location/i });
const saveButton = screen.getByRole('button', { name: /save/i });

await user.type(queueNameInput, 'Test Queue');
await user.selectOptions(serviceSelect, '6f017eb0-b035-4acd-b284-da45f5067502');
await user.selectOptions(serviceTypeSelect, '6f017eb0-b035-4acd-b284-da45f5067502');
await user.selectOptions(locationSelect, '34567eb0-b035-4acd-b284-da45f5067502');
await user.click(saveButton);

expect(queueNameInput).toHaveValue('Test Queue');
expect(serviceSelect).toHaveValue('6f017eb0-b035-4acd-b284-da45f5067502');
expect(locationSelect).toHaveValue('34567eb0-b035-4acd-b284-da45f5067502');
expect(mockShowSnackbar).toHaveBeenCalledTimes(1);
expect(mockShowSnackbar).toHaveBeenCalledWith({
isLowContrast: false,
kind: 'error',
title: expect.stringMatching(/error creating queue service/i),
subtitle: expect.stringMatching(/internal server error/i),
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,17 @@ import type { TFunction } from 'react-i18next';
import { useForm, Controller } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';

import {
Button,
ButtonSet,
Column,
Form,
InlineLoading,
Layer,
Select,
SelectItem,
Stack,
TextInput,
InlineLoading,
} from '@carbon/react';
import { mutate } from 'swr';
import { type DefaultWorkspaceProps, restBaseUrl, showSnackbar } from '@openmrs/esm-framework';
Expand All @@ -31,7 +30,7 @@ const createQueueServiceSchema = (t: TFunction) =>
})
.trim()
.min(1, t('queueNameRequired', 'Queue name is required')),
queueConcept: z
queueServiceType: z
.string({
required_error: t('queueConceptRequired', 'Queue concept is required'),
})
Expand All @@ -51,6 +50,7 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
const { t } = useTranslation();
const { queueConcepts } = useServiceConcepts();
const { queueLocations } = useQueueLocations();

const QueueServiceSchema = createQueueServiceSchema(t);

const {
Expand All @@ -61,13 +61,13 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
resolver: zodResolver(QueueServiceSchema),
defaultValues: {
queueName: '',
queueConcept: '',
queueServiceType: '',
userLocation: '',
},
});

const createQueue = (data: QueueServiceFormData) => {
saveQueue(data.queueName, data.queueConcept, '', data.userLocation)
saveQueue(data.queueName, data.queueServiceType, '', data.userLocation)
.then(() => {
showSnackbar({
title: t('queueServiceCreated', 'Queue service created'),
Expand All @@ -80,10 +80,10 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
})
.catch((error) => {
showSnackbar({
title: t('errorAddingQueue', 'Error adding queue'),
title: t('errorCreatingQueueService', 'Error creating queue service'),
kind: 'error',
isLowContrast: false,
subtitle: error?.message,
subtitle: error?.responseBody?.message || error?.message,
});
});
};
Expand All @@ -108,25 +108,19 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
/>
</Layer>
</Column>

<Column>
<Layer className={styles.input}>
<Controller
name="queueConcept"
name="queueServiceType"
control={control}
render={({ field }) => (
<Select
{...field}
labelText={t('selectServiceType', 'Select a service type')}
id="queueConcept"
disabled={queueConcepts.length === 0}
invalid={!!errors?.queueConcept}
invalidText={
errors?.queueConcept?.message ||
(queueConcepts.length === 0 ? t('noServicesAvailable', 'No services available') : '')
}>
id="queueServiceType"
invalid={!!errors?.queueServiceType}
invalidText={errors?.queueServiceType?.message}>
<SelectItem text={t('selectServiceType', 'Select a service type')} value="" />

{queueConcepts?.length > 0 &&
queueConcepts.map((concept) => (
<SelectItem key={concept.uuid} text={concept.display} value={concept.uuid}>
Expand All @@ -138,21 +132,19 @@ const QueueServiceForm: React.FC<DefaultWorkspaceProps> = ({ closeWorkspace }) =
/>
</Layer>
</Column>

<Column>
<Layer className={styles.input}>
<Controller
name="userLocation"
control={control}
render={({ field }) => (
<Select
disabled={queueLocations.length === 0}
{...field}
id="location"
invalid={errors?.userLocation}
invalid={!!errors?.userLocation}
invalidText={errors?.userLocation?.message}
labelText={t('selectALocation', 'Select a location')}>
{!field.value && <SelectItem text={t('selectALocation', 'Select a location')} value="" />}
<SelectItem text={t('selectALocation', 'Select a location')} value="" />
{queueLocations?.length > 0 &&
queueLocations.map((location) => (
<SelectItem key={location.id} text={location.name} value={location.id}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ export function useServiceConcepts() {
};
}

export function saveQueue(queueName: string, queueConcept: string, queueDescription?: string, queueLocation?: string) {
export function saveQueue(
queueName: string,
queueServiceType: string,
queueDescription?: string,
queueLocation?: string,
) {
const abortController = new AbortController();

return openmrsFetch(`${restBaseUrl}/queue`, {
return openmrsFetch(`${restBaseUrl}/queued`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Expand All @@ -24,7 +29,7 @@ export function saveQueue(queueName: string, queueConcept: string, queueDescript
body: {
name: queueName,
description: queueDescription,
service: { uuid: queueConcept },
service: { uuid: queueServiceType },
location: {
uuid: queueLocation,
},
Expand Down
7 changes: 3 additions & 4 deletions packages/esm-service-queues-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
"addNewServiceRoom": "Add new service room",
"addPatientToQueue": "Add patient to queue",
"addProviderQueueRoom": "Add provider queue room",
"addQueue": "Add queue",
"addQueueRoom": "Add queue room",
"addQueueRoomName": "Please add a queue room name",
"addQueueRoomService": "Please add a queue room service",
Expand Down Expand Up @@ -57,9 +56,9 @@
"endVisit": "End visit",
"endVisitWarningMessage": "Ending this visit will not allow you to fill another encounter form for this patient",
"enterCommentHere": "Enter Comment here",
"errorAddingQueue": "Error adding queue",
"errorAddingQueueRoom": "Error adding queue room",
"errorClearingQueues": "Error clearing queues",
"errorCreatingQueueService": "Error creating queue service",
"errorFetchingVisit": "Error fetching patient visit",
"errorLoadingQueueEntries": "Error loading queue entries",
"errorPostingToScreen": "Error posting to screen",
Expand Down Expand Up @@ -102,7 +101,6 @@
"noPrioritiesForServiceTitle": "No priorities available",
"noPriorityFound": "No priority found",
"noReturnDate": "There is no return date to display for this patient",
"noServicesAvailable": "No services available",
"noServicesConfigured": "No services configured",
"noStatusConfigured": "No status configured",
"notableConfig": "No table configuration",
Expand Down Expand Up @@ -131,7 +129,6 @@
"priorityIsRequired": "Priority is required",
"provider": "Provider",
"quantity": "Quantity",
"queueAddedSuccessfully": "Queue added successfully",
"queueConceptRequired": "Queue concept is required",
"queueEntryAddedSuccessfully": "Queue entry added successfully",
"queueEntryDeleteFailed": "Error deleting queue entry",
Expand Down Expand Up @@ -163,6 +160,8 @@
"queuesClearedSuccessfully": "Queues cleared successfully",
"queueScreen": "Queue screen",
"queueService": "Queue service",
"queueServiceCreated": "Queue service created",
"queueServiceCreatedSuccessfully": "Queue service created successfully",
"queueStatus": "Queue status",
"refills": "Refills",
"removeFromQueueAndEndVisit": "Remove patient from queue and end active visit",
Expand Down

0 comments on commit f2724f9

Please sign in to comment.