Skip to content

Commit

Permalink
(refactor) Refactor bed management app to match conventions
Browse files Browse the repository at this point in the history
This PR applies a set of changes to the bed management app to match the conventions of the other apps in the O3 ecosystem.
  • Loading branch information
denniskigen committed Nov 12, 2024
1 parent d352d9f commit 260c70a
Show file tree
Hide file tree
Showing 33 changed files with 622 additions and 573 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useCallback } from 'react';
import dayjs from 'dayjs';
import isToday from 'dayjs/plugin/isToday';
import useSWR, { useSWRConfig } from 'swr';
import { openmrsFetch, restBaseUrl } from '@openmrs/esm-framework';
import {
Expand All @@ -7,12 +9,10 @@ import {
type AppointmentsFetchResponse,
type RecurringAppointmentsPayload,
} from '../types';
import isToday from 'dayjs/plugin/isToday';
import { useCallback } from 'react';
dayjs.extend(isToday);

const appointmentUrlMatcher = '/ws/rest/v1/appointment';
const appointmentsSearchUrl = '/ws/rest/v1/appointments/search';
const appointmentUrlMatcher = `${restBaseUrl}/appointment`;
const appointmentsSearchUrl = `${restBaseUrl}/appointments/search`;

export function useMutateAppointments() {
const { mutate } = useSWRConfig();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import { ArrowRight } from '@carbon/react/icons';

const BedManagementAdminCardLink: React.FC = () => {
const { t } = useTranslation();
const header = t('manageBeds', 'Manage Beds');
const header = t('manageBeds', 'Manage beds');

return (
<Layer>
<ClickableTile href={window.getOpenmrsSpaBase() + 'bed-management'} rel="noopener noreferrer">
<div>
<div className="heading">{header}</div>
<div className="content">{t('bedManagement', 'Bed Management')}</div>
<div className="content">{t('bedManagement', 'Bed management')}</div>
</div>
<div className="iconWrapper">
<ArrowRight size={16} />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useCallback, useState } from 'react';
import capitalize from 'lodash-es/capitalize';
import { z } from 'zod';
import { useForm, Controller } from 'react-hook-form';
Expand All @@ -9,6 +9,7 @@ import {
ComposedModal,
Form,
FormGroup,
InlineNotification,
ModalBody,
ModalFooter,
ModalHeader,
Expand All @@ -18,18 +19,33 @@ import {
Stack,
TextArea,
TextInput,
InlineNotification,
} from '@carbon/react';
import { useTranslation } from 'react-i18next';
import { getCoreTranslation, type Location } from '@openmrs/esm-framework';
import type { BedType, BedFormData } from '../types';
import { type BedAdministrationData } from './bed-administration-types';
import { type BedType, type BedFormData } from '../types';

interface BedAdministrationFormProps {
allLocations: Location[];
availableBedTypes: Array<BedType>;
handleCreateBed?: (formData: BedAdministrationData) => void;
headerTitle: string;
initialData: BedFormData;
occupancyStatuses: string[];
onModalChange: (showModal: boolean) => void;
showModal: boolean;
}

interface ErrorType {
message: string;
}

const numberInString = z.string().transform((val, ctx) => {
const parsed = parseInt(val);
if (isNaN(parsed) || parsed < 1) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
// TODO: Translate this message
message: 'Please enter a valid number',
});
return z.NEVER;
Expand All @@ -38,52 +54,33 @@ const numberInString = z.string().transform((val, ctx) => {
});

const BedAdministrationSchema = z.object({
bedColumn: numberInString,
bedId: z.string().max(255),
description: z.string().max(255),
bedRow: numberInString,
bedColumn: numberInString,
bedType: z.string().refine((value) => value != '', 'Please select a valid bed type'),
description: z.string().max(255),
location: z
.object({ display: z.string(), uuid: z.string() })
.refine((value) => value.display != '', 'Please select a valid location'),
occupancyStatus: z.string().refine((value) => value != '', 'Please select a valid occupied status'),
bedType: z.string().refine((value) => value != '', 'Please select a valid bed type'),
});

interface BedAdministrationFormProps {
showModal: boolean;
onModalChange: (showModal: boolean) => void;
availableBedTypes: Array<BedType>;
allLocations: Location[];
handleCreateQuestion?: (formData: BedAdministrationData) => void;
headerTitle: string;
occupancyStatuses: string[];
initialData: BedFormData;
}

interface ErrorType {
message: string;
}

const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
showModal,
onModalChange,
availableBedTypes,
allLocations,
handleCreateQuestion,
availableBedTypes,
handleCreateBed,
headerTitle,
occupancyStatuses,
initialData,
occupancyStatuses,
onModalChange,
showModal,
}) => {
const { t } = useTranslation();
const [occupancyStatus, setOccupancyStatus] = useState(capitalize(initialData.status));
const [selectedBedType] = useState(initialData.bedType?.name ?? '');
const [showErrorNotification, setShowErrorNotification] = useState(false);
const [formStateError, setFormStateError] = useState('');

const filterLocationNames = (location) => {
return location.item.display?.toLowerCase().includes(location?.inputValue?.toLowerCase()) ?? [];
};

const {
handleSubmit,
control,
Expand All @@ -92,21 +89,21 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
mode: 'all',
resolver: zodResolver(BedAdministrationSchema),
defaultValues: {
bedColumn: initialData.column.toString() ?? '0',
bedId: initialData.bedNumber ?? '',
description: initialData.bedType?.description ?? '',
bedRow: initialData.row.toString() ?? '0',
bedColumn: initialData.column.toString() ?? '0',
bedType: initialData.bedType?.name ?? '',
description: initialData.bedType?.description ?? '',
location: initialData.location ?? {},
occupancyStatus: capitalize(initialData.status) ?? occupancyStatus,
bedType: initialData.bedType?.name ?? '',
},
});

const onSubmit = (formData: BedAdministrationData) => {
const result = BedAdministrationSchema.safeParse(formData);
if (result.success) {
setShowErrorNotification(false);
handleCreateQuestion(formData);
handleCreateBed(formData);
}
};

Expand All @@ -116,6 +113,7 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
};

return (
// TODO: Port this over to the modal system or create individual modals for each form
<ComposedModal open={showModal} onClose={() => onModalChange(false)} preventCloseOnClickOutside>
<ModalHeader title={headerTitle} />
<ModalBody hasScrollingContent>
Expand All @@ -129,9 +127,9 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
<>
<TextInput
id="bedId"
labelText={t('bedId', 'Bed number')}
placeholder={t('bedIdPlaceholder', 'e.g. BMW-201')}
invalidText={fieldState.error?.message}
labelText={t('bedNumber', 'Bed number')}
placeholder={t('enterBedNumber', 'e.g. BMW-201')}
{...field}
/>
</>
Expand All @@ -146,12 +144,12 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
render={({ field, fieldState }) => (
<>
<TextArea
rows={2}
id="description"
invalidText={fieldState?.error?.message}
labelText={t('description', 'Bed description')}
labelText={t('bedDescription', 'Bed description')}
placeholder={t('enterBedDescription', 'Enter the bed description')}
rows={2}
{...field}
placeholder={t('description', 'Enter the bed description')}
/>
</>
)}
Expand All @@ -166,9 +164,9 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
<NumberInput
hideSteppers
id="bedRow"
invalidText={fieldState?.error?.message}
label="Bed row"
labelText="Bed row"
invalidText={fieldState?.error?.message}
{...field}
/>
)}
Expand Down Expand Up @@ -199,18 +197,18 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
render={({ fieldState, field: { onChange, onBlur, value, ref } }) => (
<ComboBox
aria-label={t('location', 'Location')}
shouldFilterItem={filterLocationNames}
id="location"
label={t('location', 'Location')}
invalidText={fieldState?.error?.message}
items={allLocations}
itemToString={(location) => location?.display ?? ''}
label={t('location', 'Location')}
onBlur={onBlur}
ref={ref}
selectedItem={value}
onChange={({ selectedItem }) => onChange(selectedItem)}
itemToString={(location) => location?.display ?? ''}
placeholder={t('selectBedLocation', 'Select a bed location')}
ref={ref}
selectedItem={value}
titleText={t('bedLocation', 'Location')}
typeahead
/>
)}
/>
Expand All @@ -222,19 +220,19 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
control={control}
render={({ field, fieldState }) => (
<Select
defaultValue={occupancyStatus}
id="occupancyStatus"
labelText={t('occupancyStatus', 'Occupied Status')}
invalidText={fieldState.error?.message}
defaultValue={occupancyStatus}
labelText={t('occupancyStatus', 'Occupancy status')}
onChange={(event) => setOccupancyStatus(event.target.value)}
value={occupancyStatus}
{...field}>
<SelectItem text={t('chooseOccupiedStatus', 'Choose occupied status')} value="" />
{occupancyStatuses.map((occupancyStatus, index) => (
<SelectItem
key={`occupancyStatus-${index}`}
text={t('occupancyStatus', `${occupancyStatus}`)}
value={t('occupancyStatus', `${occupancyStatus}`)}
key={`occupancyStatus-${index}`}
/>
))}
</Select>
Expand All @@ -248,10 +246,10 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
control={control}
render={({ field }) => (
<Select
defaultValue={selectedBedType}
id="bedType"
labelText={t('bedType', 'Bed type')}
invalidText={t('required', 'Required')}
defaultValue={selectedBedType}
labelText={t('bedType', 'Bed type')}
{...field}>
<SelectItem text={t('chooseBedtype', 'Choose a bed type')} />
{availableBedTypes.map((bedType, index) => (
Expand All @@ -265,13 +263,13 @@ const BedAdministrationForm: React.FC<BedAdministrationFormProps> = ({
</FormGroup>
{showErrorNotification && (
<InlineNotification
kind="error"
lowContrast
title={t('error', 'Error')}
style={{ minWidth: '100%', margin: '0', padding: '0' }}
onClose={() => setShowErrorNotification(false)}
role="alert"
kind="error"
style={{ minWidth: '100%', margin: '0', padding: '0' }}
subtitle={t('pleaseFillField', formStateError) + '.'}
onClose={() => setShowErrorNotification(false)}
title={t('error', 'Error')}
/>
)}
</Stack>
Expand Down
Empty file.
Loading

0 comments on commit 260c70a

Please sign in to comment.