Skip to content

Commit

Permalink
add more queue columns
Browse files Browse the repository at this point in the history
  • Loading branch information
chibongho committed Apr 30, 2024
1 parent d4fd2a1 commit 482fd53
Show file tree
Hide file tree
Showing 21 changed files with 463 additions and 230 deletions.
2 changes: 1 addition & 1 deletion packages/esm-service-queues-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"test:watch": "cross-env TZ=UTC jest --watch --config jest.config.js --color",
"coverage": "yarn test --coverage",
"typescript": "tsc",
"extract-translations": "i18next 'src/**/*.component.tsx' --config ../../tools/i18next-parser.config.js"
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.resource.ts' --config ../../tools/i18next-parser.config.js"
},
"browserslist": [
"extends browserslist-config-openmrs"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,28 @@
import React from 'react';
import TransitionMenu from '../queue-entry-table-components/transition-entry.component';
import { type QueueTableColumnFunction, type QueueTableCellComponentProps, type QueueTableColumn } from '../types';
import { type QueueEntry } from '../types';
import ActionsMenu from '../queue-entry-table-components/actions-menu.component';
import EditMenu from '../queue-entry-table-components/edit-entry.component';
import { useConfig } from '@openmrs/esm-framework';
import { type ConfigObject } from '../config-schema';
import { mapVisitQueueEntryProperties } from './active-visits-table.resource';
import styles from './active-visits-row-actions.scss';
interface ActiveVisitRowActionsCellProps {
state: {
queueEntry: QueueEntry;
};
}

// table column definition containing actions user can perform to each row.
export const ActiveVisitRowActionsCell = ({ queueEntry }: QueueTableCellComponentProps) => {
// This component is meant to be mounted as an extension in the queue-table-extension-column-slot.
// Defines the following actions the user can perform on a queue entry:
// - queue / requeue (to the in-service status)
// - transfer to a different queue
// - Overflow menu action to edit patient detail
// - Overflow menu action to end patient visit
const ActiveVisitRowActionsCell = ({ state: { queueEntry } }: ActiveVisitRowActionsCellProps) => {
const { visitQueueNumberAttributeUuid } = useConfig<ConfigObject>();

const mappedQueueEntry = mapVisitQueueEntryProperties(queueEntry, visitQueueNumberAttributeUuid);
const mappedQueueEntry = mapVisitQueueEntryProperties(queueEntry as QueueEntry, visitQueueNumberAttributeUuid);

return (
<>
Expand All @@ -25,9 +35,4 @@ export const ActiveVisitRowActionsCell = ({ queueEntry }: QueueTableCellComponen
);
};

export const activeVisitActionsColumn: QueueTableColumnFunction = (key, header) => ({
key,
header,
CellComponent: ActiveVisitRowActionsCell,
getFilterableValue: null,
});
export default ActiveVisitRowActionsCell;
117 changes: 71 additions & 46 deletions packages/esm-service-queues-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,58 @@ import biometricsConfigSchema, {
type BiometricsConfigObject,
} from './current-visit/visit-details/biometrics-config-schema';

// Not all of the columnDefinitions are used below, but they are defined anyway
// for demonstration purpose. Implementors can copy this JSON as a starting point
// to configure the queue tables
export const defaultTablesConfig: TablesConfig = {
columnDefinitions: [
{
id: 'patient-name',
columnType: 'patient-name-column',
},
{
id: 'patient-id',
columnType: 'patient-id-column',
id: 'patient-age',
columnType: 'patient-age-column',
},
{
id: 'patient-identifier',
columnType: 'patient-identifier-column',
config: {
identifierType: 'openmrs-id-uuid',
identifierType: 'patient-identifier-uuid',
},
},
{
id: 'priority',
columnType: 'priority-column',
config: [],
},
{
id: 'comingFrom',
columnType: 'queue-coming-from-column',
config: {
priorities: [
{
conceptUuid: 'priority-concept-uuid',
tagClassName: 'tag',
tagType: 'red',
},
],
},
},
{
id: 'status',
columnType: 'status-column',
config: [],
config: {
statuses: [
{
conceptUuid: 'status-concept-uuid',
iconComponent: 'InProgress',
},
],
},
},
{
id: 'visit-start-time',
columnType: 'visit-start-time-column',
},
{
id: 'comingFrom',
columnType: 'queue-coming-from-column',
},
{
id: 'queue',
Expand All @@ -41,37 +67,19 @@ export const defaultTablesConfig: TablesConfig = {
},
{
id: 'actions',
columnType: 'active-visits-actions-column',
columnType: 'extension-column',
header: 'Actions',
},
],
tableDefinitions: [
{
columns: ['patient-name', 'priority', 'comingFrom', 'status', 'wait-time', 'actions'],
appliedTo: { queue: '3113f164-68f0-11ee-ab8d-0242ac120002' },
},
{
columns: ['patient-name', 'patient-id', 'comingFrom', 'priority', 'status', 'queue', 'wait-time', 'actions'],
columns: ['patient-name', 'comingFrom', 'priority', 'status', 'queue', 'wait-time', 'actions'],
appliedTo: [{ queue: null, status: null }],
},
],
};

export const configSchema = {
priorityConfigs: {
_type: Type.Array,
_element: {
_type: Type.Object,
},
_description: 'Allows customization of how specific priorities are rendered',
_default: [],
},
statusConfigs: {
_type: Type.Array,
_element: {
_type: Type.Object,
},
_description: 'Allows customization of how specific statuses are rendered',
_default: [],
},
concepts: {
defaultPriorityConceptUuid: {
_type: Type.ConceptUuid,
Expand Down Expand Up @@ -182,14 +190,19 @@ export const configSchema = {
},
tablesConfig: {
_type: Type.Object,
_description: 'TODO',
_description: `Configurations of columns to show for the queue table.
Multiple configurations can be provided, each can be applied generally, or to tables
for a particular queue, particular status, or even particular queue+status combination.
If multiple configs are defined, the first config with matching appliedTo condition
is used.
See https://github.com/openmrs/openmrs-esm-patient-management/blob/main/packages/esm-service-queues-app/src/config-schema.ts
for full schema definition and example.
`,
_default: defaultTablesConfig,
},
};

export interface ConfigObject {
priorityConfigs: Array<PriorityConfig>;
statusConfigs: Array<StatusConfig>;
concepts: {
defaultPriorityConceptUuid: string;
defaultStatusConceptUuid: string;
Expand Down Expand Up @@ -231,27 +244,27 @@ interface TablesConfig {

export type ColumnDefinition = {
id: string;
header?: string; // custom translation key for the column's header; overrides the default one
header?: string; // optional custom i18n translation key for the column's header; overrides the default one
headerModule?: string; // optional custom i18n translation module for the column's header. Must be used with the header option
} & (
| { columnType: 'patient-name-column' }
| { columnType: 'patient-id-column'; config: PatientIdColumnConfig }
| { columnType: 'patient-identifier-column'; config: PatientIdentifierColumnConfig }
| { columnType: 'patient-age-column' }
| { columnType: 'priority-column'; config: PriorityColumnConfig }
| { columnType: 'status-column'; config: StatusColumnConfig }
| { columnType: 'priority-column'; config?: PriorityColumnConfig }
| { columnType: 'status-column'; config?: StatusColumnConfig }
| { columnType: 'queue-coming-from-column' }
| { columnType: 'current-queue-column' }
| { columnType: 'wait-time-column' }
| { columnType: 'visit-start-time-column' }
| { columnType: 'actions-column' }
| { columnType: 'active-visits-actions-column' }
| { columnType: 'extension-column'; config: object }
| { columnType: 'extension-column'; config?: object } // column that contains the extension slot queue-table-extension-column-slot
);

export interface VisitAttributeQueueNumberColmnConfig {
export interface VisitAttributeQueueNumberColumnConfig {
visitQueueNumberAttributeUuid: string;
}

export interface PatientIdColumnConfig {
export interface PatientIdentifierColumnConfig {
identifierType: string; // uuid of the identifier type
}
export interface PriorityConfig {
Expand All @@ -260,16 +273,28 @@ export interface PriorityConfig {
tagClassName: 'priorityTag' | 'tag' | null;
}

export type PriorityColumnConfig = PriorityConfig[];
export interface PriorityColumnConfig {
priorities: PriorityConfig[];
}

export interface StatusConfig {
conceptUuid: string;
iconComponent: 'Group' | 'InProgress' | null;
}

export type StatusColumnConfig = StatusConfig[];
export interface StatusColumnConfig {
statuses: StatusConfig[];
}

export interface ExtensionColumnConfig {
state: any; // state to pass into the extension
}

export interface TableDefinitions {
columns: string[]; // a list of columnIds
appliedTo?: { queue?: string; status?: string };
// a list of column ids defined in columnDefinitions
columns: string[];

// apply the columns to tables of any of the specified queue and status
// (if appliedTo is null, apply to all tables, including the one in the service queue app home page)
appliedTo?: Array<{ queue?: string; status?: string }>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { type QueueEntry, type QueueEntrySearchCriteria } from '../types';
import useSWR from 'swr';

const repString =
'custom:(uuid,display,queue,status,patient,visit:(uuid,display,encounters:(uuid,display,diagnoses,encounterDatetime,encounterType,obs,encounterProviders,voided)),priority,priorityComment,sortWeight,startedAt,endedAt,locationWaitingFor,queueComingFrom,providerWaitingFor,previousQueueEntry)';
'custom:(uuid,display,queue,status,patient,visit:(uuid,display,startDatetime,encounters:(uuid,display,diagnoses,encounterDatetime,encounterType,obs,encounterProviders,voided)),priority,priorityComment,sortWeight,startedAt,endedAt,locationWaitingFor,queueComingFrom,providerWaitingFor,previousQueueEntry)';

export function useQueueEntries(searchCriteria?: QueueEntrySearchCriteria, rep: string = repString) {
const searchParam = new URLSearchParams();
Expand Down
9 changes: 9 additions & 0 deletions packages/esm-service-queues-app/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ export const voidQueueEntryModal = getAsyncLifecycle(

export const addQueueEntry = getSyncLifecycle(addQueueEntryComponent, options);

export const activeVisitsRowActions = getAsyncLifecycle(
() => import('./active-visits/active-visits-row-actions.component'),
{
featureName:
'quick actions to queue, requeue and transfer patients. With overflow menu actions to edit patient and end visit',
moduleName,
},
);

export function startupApp() {
registerBreadcrumbs([]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React from 'react';
import { DefinitionTooltip, Tag } from '@carbon/react';
import styles from './queue-priority.scss';
import { type ConfigObject } from '../config-schema';
import { type PriorityConfig } from '../config-schema';
import { type Concept } from '../types';
import { useConfig } from '@openmrs/esm-framework';

interface QueuePriorityProps {
priority: Concept;
priorityComment?: string;
priorityConfigs: PriorityConfig[];
}

const QueuePriority: React.FC<QueuePriorityProps> = ({ priority, priorityComment }) => {
const { priorityConfigs } = useConfig<ConfigObject>();
const QueuePriority: React.FC<QueuePriorityProps> = ({ priority, priorityComment, priorityConfigs }) => {
const priorityConfig = priorityConfigs?.find((c) => c.conceptUuid === priority.uuid);
return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import React from 'react';
import { Group, InProgress } from '@carbon/react/icons';
import styles from '../queue-table/queue-table.scss';
import { type Concept, type Queue } from '../types';
import { useConfig } from '@openmrs/esm-framework';
import { type ConfigObject, type StatusConfig } from '../config-schema';
import { type StatusConfig } from '../config-schema';

interface QueueStatusProps {
status: Concept;
queue?: Queue;
statusConfigs: StatusConfig[];
}

const QueueStatus: React.FC<QueueStatusProps> = ({ status, queue }) => {
const { statusConfigs } = useConfig<ConfigObject>();
const QueueStatus: React.FC<QueueStatusProps> = ({ status, queue, statusConfigs }) => {
const statusConfig = statusConfigs?.find((c) => c.conceptUuid === status.uuid);
return (
<span className={styles.statusContainer}>
Expand Down

0 comments on commit 482fd53

Please sign in to comment.