Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat KHP3-7061: Implement UI improvements on the admit workspace #459

Merged
merged 5 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions packages/esm-morgue-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,31 @@ export const configSchema = {
_description: 'UUID for ob number concept',
_default: '682bd161-1ff0-40d6-95b6-f7c5d955bb4d',
},
policeNameUuid: {
_type: Type.String,
_description: 'UUID for police name concept',
_default: '18ad3028-94c5-4ac0-80de-97267bd96ffa',
},
burialPermitNumberUuid: {
_type: Type.String,
_description: 'UUID for burial permit number concept',
_default: 'a4157d5d-deb2-438e-9948-8152ed1fe157',
},
policeIDNumber: {
_type: Type.String,
_description: 'UUID for police id number concept',
_default: 'c8d5a5b4-6589-4833-83f4-af75d74d3d38',
},
encounterProviderRoleUuid: {
_type: Type.UUID,
_default: 'a0b03050-c99b-11e0-9572-0800200c9a66',
_description: "The provider role to use for the registration encounter. Default is 'Unkown'.",
},
dischargeAreaUuid: {
_type: Type.String,
_description: 'UUID for discharge area concept',
_default: '3f908c18-6ef6-4f7d-a217-254d067cc148',
},
};

export interface BillingConfig {
Expand Down Expand Up @@ -103,4 +123,8 @@ export type ConfigObject = {
policeStatementUuid: string;
obNumberUuid: string;
encounterProviderRoleUuid: string;
policeNameUuid: string;
burialPermitNumberUuid: string;
policeIDNumber: string;
dischargeAreaUuid: string;
};
111 changes: 66 additions & 45 deletions packages/esm-morgue-app/src/tables/generic-table.component.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import classNames from 'classnames';
import { useTranslation } from 'react-i18next';
import {
Expand All @@ -15,6 +15,7 @@ import {
import { CardHeader, PatientChartPagination } from '@openmrs/esm-patient-common-lib';
import { useLayoutType, usePagination } from '@openmrs/esm-framework';
import styles from './generic-table.scss';
import EmptyDeceasedSearch from '../empty-state/empty-search-deceased.component';

interface GenericTableProps {
rows: any[];
Expand All @@ -26,9 +27,16 @@ interface GenericTableProps {
const GenericTable: React.FC<GenericTableProps> = ({ rows, headers, actionColumn, title }) => {
const { t } = useTranslation();
const pageSize = 10;
const { results: paginatedData, currentPage, goTo } = usePagination(rows, pageSize);
const isTablet = useLayoutType() === 'tablet';

const [searchTerm, setSearchTerm] = useState('');

const filteredRows = rows.filter((row) =>
headers.some((header) => row[header.key]?.toString().toLowerCase().includes(searchTerm.toLowerCase())),
);

const { results: paginatedData, currentPage, goTo } = usePagination(filteredRows, pageSize);

return (
<div className={styles.table}>
<CardHeader title={title} children={''} />
Expand All @@ -39,54 +47,67 @@ const GenericTable: React.FC<GenericTableProps> = ({ rows, headers, actionColumn
labelText="Search"
closeButtonLabelText="Clear search input"
id="search-deceased"
onChange={() => {}}
onKeyDown={() => {}}
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className={styles.searchInput}
/>
</div>
<div className={styles.genericTable}>
<DataTable rows={paginatedData} headers={headers} isSortable size={isTablet ? 'lg' : 'sm'} useZebraStyles>
{({ rows, headers, getHeaderProps, getTableProps }) => (
<TableContainer className={styles.tableContainer}>
<Table {...getTableProps()}>
<TableHead>
<TableRow>
{headers.map((header) => (
<TableHeader
key={header.key}
className={classNames(styles.productiveHeading01, styles.text02)}
{...getHeaderProps({
header,
isSortable: header.isSortable,
})}>
{header.header}
</TableHeader>
))}
{<TableHeader>{t('action', 'Action')}</TableHeader>}
</TableRow>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.id}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>

{rows.length === 0 ? (
<EmptyDeceasedSearch
title={t('noWaitingList', 'Waiting List')}
subTitle={t('noDeceasedPersons', 'There are no deceased persons on the waiting list')}
/>
) : searchTerm && filteredRows.length === 0 ? (
<EmptyDeceasedSearch
title={t('noResultFound', 'Sorry, no results found')}
subTitle={t('searchForADeceased', "Try to search again using the deceased patient's unique ID number")}
/>
) : (
<div className={styles.genericTable}>
<DataTable rows={paginatedData} headers={headers} isSortable size={isTablet ? 'lg' : 'sm'} useZebraStyles>
{({ rows, headers, getHeaderProps, getTableProps }) => (
<TableContainer className={styles.tableContainer}>
<Table {...getTableProps()}>
<TableHead>
<TableRow>
{headers.map((header) => (
<TableHeader
key={header.key}
className={classNames(styles.productiveHeading01, styles.text02)}
{...getHeaderProps({
header,
isSortable: header.isSortable,
})}>
{header.header}
</TableHeader>
))}
{actionColumn && <TableCell>{actionColumn(row)}</TableCell>}
{actionColumn && <TableHeader>Action</TableHeader>}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
</DataTable>
<PatientChartPagination
currentItems={paginatedData.length}
totalItems={rows.length}
onPageNumberChange={({ page }) => goTo(page)}
pageNumber={currentPage}
pageSize={pageSize}
/>
</div>
</TableHead>
<TableBody>
{rows.map((row) => (
<TableRow key={row.id}>
{row.cells.map((cell) => (
<TableCell key={cell.id}>{cell.value}</TableCell>
))}
{actionColumn && <TableCell>{actionColumn(row)}</TableCell>}
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
)}
</DataTable>
<PatientChartPagination
currentItems={paginatedData.length}
totalItems={filteredRows.length}
onPageNumberChange={({ page }) => goTo(page)}
pageNumber={currentPage}
pageSize={pageSize}
/>
</div>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ const patientInfoSchema = z.object({
.regex(/^(0[1-9]|1[0-2]):[0-5][0-9]\s?(AM|PM)$/i, 'Time of death must be in the format hh:mm AM/PM'),
tagNumber: z.string().nonempty('Tag number is required'),
obNumber: z.string().optional(),
policeName: z.string().optional(),
policeIDNo: z.string().optional(),
dischargeArea: z.string().optional(),
burialPermitNo: z.string().nonempty('Burial Permit is required'),
visitType: z.string().uuid('invalid visit type'),
availableCompartment: z.string(),
services: z.array(z.string().uuid('invalid service')).nonempty('Must select one service'),
Expand Down Expand Up @@ -101,9 +105,12 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
visitPaymentMethodAttributeUuid,
morgueAdmissionEncounterType,
tagNumberUuid,
policeStatementUuid,
policeIDNumber,
policeNameUuid,
burialPermitNumberUuid,
obNumberUuid,
encounterProviderRoleUuid,
dischargeAreaUuid,
} = useConfig<ConfigObject>();

const [searchTerm, setSearchTerm] = useState<string>('');
Expand All @@ -122,10 +129,14 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
timeOfDeath: '',
tagNumber: '',
obNumber: '',
policeName: '',
policeIDNo: '',
burialPermitNo: '',
visitType: morgueVisitTypeUuid,
availableCompartment: '',
paymentMethod: '',
insuranceScheme: '',
dischargeArea: '',
policyNumber: '',
services: [],
},
Expand Down Expand Up @@ -177,6 +188,18 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
if (data.obNumber) {
obs.push({ concept: obNumberUuid, value: data.obNumber });
}
if (data.policeName) {
obs.push({ concept: policeNameUuid, value: data.policeName });
}
if (data.policeIDNo) {
obs.push({ concept: policeIDNumber, value: data.policeIDNo });
}
if (data.burialPermitNo) {
obs.push({ concept: burialPermitNumberUuid, value: data.burialPermitNo });
}
if (data.dischargeArea) {
obs.push({ concept: dischargeAreaUuid, value: data.dischargeArea });
}

const encounterPayload = {
visit: {
Expand Down Expand Up @@ -478,14 +501,32 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
)}
/>
</Column>
<Column>
<Controller
name="dischargeArea"
control={control}
render={({ field }) => (
<TextInput
{...field}
id="dischargeArea"
className={styles.sectionField}
placeholder={t('dischargeArea', 'Discharge Area')}
labelText={t('dischargeArea', 'Discharge Area')}
invalid={!!errors.dischargeArea}
invalidText={errors.dischargeArea?.message}
/>
)}
/>
</Column>

<Column>
<ComboBox
<Dropdown
onChange={(e) => handlePoliceCaseChange(e.selectedItem)}
id="morgue-combobox"
className={styles.formAdmissionDatepicker}
items={['Yes', 'No']}
itemToString={(item) => (item ? item : '')}
label={t('ChooseOptions', 'Choose option')}
titleText={t(
'isPoliceCase',
'Is the body associated with a police case? If so, can you provide the OB number?*',
Expand All @@ -504,10 +545,45 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
{...field}
id="obNumber"
className={styles.formAdmissionDatepicker}
placeholder={t('obNumber', 'OB Number*')}
labelText={t('obNumber', 'OB Number*')}
placeholder={t('obNos', 'OB Number')}
labelText={t('obNumber', 'OB Number')}
invalid={!!errors.obNumber}
invalidText={errors.obNumber?.message}
label={t('ChooseOptions', 'Choose option')}
/>
)}
/>
</Column>
<Column>
<Controller
name="policeName"
control={control}
render={({ field }) => (
<TextInput
{...field}
id="policeName"
className={styles.formAdmissionDatepicker}
placeholder={t('policeNames', 'Police Name')}
labelText={t('policeName', 'Police name')}
invalid={!!errors.policeName}
invalidText={errors.policeName?.message}
/>
)}
/>
</Column>
<Column>
<Controller
name="policeIDNo"
control={control}
render={({ field }) => (
<TextInput
{...field}
id="policeIDNo"
className={styles.formAdmissionDatepicker}
placeholder={t('policeID', 'Police ID number')}
labelText={t('policeIDNo', 'Police ID number')}
invalid={!!errors.policeIDNo}
invalidText={errors.policeIDNo?.message}
/>
)}
/>
Expand All @@ -529,6 +605,7 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
morgueCompartments.find((compartment) => compartment.uuid === item)?.display ?? ''
}
titleText={t('availableCompartment', 'Available Compartment')}
label={t('ChooseOptions', 'Choose option')}
onChange={({ selectedItem }) => field.onChange(selectedItem)}
initialSelectedItems={field.value}
invalid={!!errors.availableCompartment}
Expand All @@ -537,6 +614,23 @@ const PatientAdditionalInfoForm: React.FC<PatientAdditionalInfoFormProps> = ({ c
)}
/>
</Column>
<Column>
<Controller
name="burialPermitNo"
control={control}
render={({ field }) => (
<TextInput
{...field}
id="burialPermitNo"
className={styles.formAdmissionDatepicker}
placeholder={t('burialPermitNo', 'Burial permit number')}
labelText={t('burialPermitNumber', 'Burial permit number')}
invalid={!!errors.burialPermitNo}
invalidText={errors.burialPermitNo?.message}
/>
)}
/>
</Column>
<ButtonSet className={styles.buttonSet}>
<Button style={{ maxWidth: '65%' }} size="lg" kind="secondary" onClick={closeWorkspace}>
{t('discard', 'Discard')}
Expand Down
5 changes: 4 additions & 1 deletion packages/esm-morgue-app/translations/en.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"action": "Action",
"admissionForm": "Admission form",
"admit": "Admit",
"admitted": "Admitted Bodies",
Expand All @@ -11,8 +10,12 @@
"discharges": "Discharges",
"empty": "Empty",
"morgue": "Morgue Management",
"noDeceasedPersons": "There are no deceased persons on the waiting list",
"noResultFound": "Sorry, no results found",
"noWaitingList": "Waiting List",
"pullingCompartment": "Pulling compartments data.....",
"release": "Release",
"searchForADeceased": "Try to search again using the deceased patient's unique ID number",
"waitingInLine": "Waiting In Line",
"waitingQueue": "Waiting queue",
"waitQueue": "Waiting queue"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,7 @@ const ProviderForm: React.FC<ProvideModalProps> = ({ closeWorkspace, provider, u
titleText="Roles*"
initialSelectedItems={field.value}
items={definedRoles}
placeholder="Confirm password"
itemToString={(item) => roles.find((r) => r.uuid === item)?.display ?? ''}
onChange={({ selectedItems }) => {
field.onChange(selectedItems);
Expand Down
Loading