Skip to content

Commit

Permalink
Merge branch 'main' into feat/metrics
Browse files Browse the repository at this point in the history
  • Loading branch information
kb019 authored Aug 29, 2024
2 parents 6a7e24d + ab41846 commit 82d3d9d
Show file tree
Hide file tree
Showing 38 changed files with 2,005 additions and 1,520 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ const CalendarHeader: React.FC = () => {
<div className={styles.calendarHeaderContainer}>
<div className={styles.titleContainer}>
<Button
className={styles.backButton}
kind="ghost"
onClick={backButtonOnClick}
renderIcon={ArrowLeft}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,18 @@
align-items: center;
}

.backButton {
svg {
order: 1;
margin-right: layout.$spacing-03;
margin-left: 0 !important;
}

span {
order: 2;
}
}

// Overriding styles for RTL support
html[dir='rtl'] {
.titleContent {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import dayjs from 'dayjs';
import React from 'react';
import classNames from 'classnames';
import dayjs from 'dayjs';
import styles from './days-of-week.scss';

interface DaysOfWeekProp {
interface DaysOfWeekProps {
dayOfWeek: string;
}
const DaysOfWeekCard: React.FC<DaysOfWeekProp> = ({ dayOfWeek }) => {

const DaysOfWeekCard: React.FC<DaysOfWeekProps> = ({ dayOfWeek }) => {
const isToday = dayjs(new Date()).format('ddd').toUpperCase() === dayOfWeek;
return (
<div tabIndex={0} role="button" className={styles.tileContainer}>
<span className={isToday ? styles.bold : ''}>{dayOfWeek}</span>
<span className={classNames({ [styles.bold]: isToday })}>{dayOfWeek}</span>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
width: 100%;
align-items: center;
border: 1px solid colors.$gray-20;
border-right: none;

&:last-child {
border-right: 1px solid colors.$gray-20;
}

& > span {
font-size: layout.$spacing-05;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import isBetween from 'dayjs/plugin/isBetween';
import { type DailyAppointmentsCountByService } from '../../types';
import { monthDays } from '../../helpers';
import MonthlyViewWorkload from './monthly-workload-view.component';
import MonthlyHeader from './monthly-header.module';
import styles from '../appointments-calendar-view-view.scss';
import MonthlyHeader from './monthly-header.component';
import SelectedDateContext from '../../hooks/selectedDateContext';
import styles from '../appointments-calendar-view-view.scss';

dayjs.extend(isBetween);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React, { useCallback, useContext } from 'react';
import dayjs from 'dayjs';
import { useTranslation } from 'react-i18next';
import { Button } from '@carbon/react';
import { formatDate } from '@openmrs/esm-framework';
import { omrsDateFormat } from '../../constants';
import DaysOfWeekCard from './days-of-week.component';
import SelectedDateContext from '../../hooks/selectedDateContext';
import styles from './monthly-header.scss';

const DAYS_IN_WEEK = ['SUN', 'MON', 'TUE', 'WED', 'THUR', 'FRI', 'SAT'];

const MonthlyHeader: React.FC = () => {
const { t } = useTranslation();
const { selectedDate, setSelectedDate } = useContext(SelectedDateContext);

const handleSelectPrevMonth = useCallback(() => {
setSelectedDate(dayjs(selectedDate).subtract(1, 'month').format(omrsDateFormat));
}, [selectedDate, setSelectedDate]);

const handleSelectNextMonth = useCallback(() => {
setSelectedDate(dayjs(selectedDate).add(1, 'month').format(omrsDateFormat));
}, [selectedDate, setSelectedDate]);

return (
<>
<div className={styles.container}>
<Button
aria-label={t('previousMonth', 'Previous month')}
kind="tertiary"
onClick={handleSelectPrevMonth}
size="sm">
{t('prev', 'Prev')}
</Button>
<span>{formatDate(new Date(selectedDate), { day: false, time: false, noToday: true })}</span>
<Button aria-label={t('nextMonth', 'Next month')} kind="tertiary" onClick={handleSelectNextMonth} size="sm">
{t('next', 'Next')}
</Button>
</div>
<div className={styles.workLoadCard}>
{DAYS_IN_WEEK.map((day) => (
<DaysOfWeekCard key={day} dayOfWeek={day} />
))}
</div>
</>
);
};

export default MonthlyHeader;

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@
text-align: right;
@include type.type-style('body-compact-02');

&:nth-child(-n + 7) {
border-top: 1px solid colors.$gray-20;
}

&:nth-child(7n) {
border-right: 1px solid colors.$gray-20;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/esm-appointments-app/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
"location": "Location",
"medications": "Medications",
"missed": "Missed",
"next": "Next",
"nextMonth": "Next month",
"nextPage": "Next page",
"no": "No",
"noAppointmentsToDisplay": "No appointments to display",
Expand All @@ -120,6 +122,8 @@
"patientName": "Patient name",
"patients": "Patients",
"period": "Period",
"prev": "Prev",
"previousMonth": "Previous month",
"previousPage": "Previous page",
"provider": "Provider",
"providers": "Providers",
Expand Down
2 changes: 1 addition & 1 deletion packages/esm-patient-registration-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' 'src/**/*.extension.tsx' 'src/**/*modal.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' --config ../../tools/i18next-parser.config.js"
"extract-translations": "i18next 'src/**/*.component.tsx' 'src/**/*.extension.tsx' 'src/**/*modal.tsx' 'src/**/*.workspace.tsx' 'src/index.ts' 'src/patient-registration/validation/patient-registration-validation.ts' --config ../../tools/i18next-parser.config.js"
},
"browserslist": [
"extends browserslist-config-openmrs"
Expand Down
30 changes: 28 additions & 2 deletions packages/esm-patient-registration-app/src/config-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ export interface RegistrationConfig {
sectionDefinitions: Array<SectionDefinition>;
fieldDefinitions: Array<FieldDefinition>;
fieldConfigurations: {
causeOfDeath: {
conceptUuid: string;
required?: boolean;
};
name: {
displayMiddleName: boolean;
allowUnidentifiedPatients: boolean;
Expand Down Expand Up @@ -78,6 +82,7 @@ export interface RegistrationConfig {
encounterProviderRoleUuid: string;
registrationFormUuid: string | null;
};
freeTextFieldConceptUuid: string;
}

export const builtInSections: Array<SectionDefinition> = [
Expand All @@ -87,12 +92,21 @@ export const builtInSections: Array<SectionDefinition> = [
fields: ['name', 'gender', 'dob', 'id'],
},
{ id: 'contact', name: 'Contact Details', fields: ['address', 'phone'] },
{ id: 'death', name: 'Death Info', fields: [] },
{ id: 'death', name: 'Death Info', fields: ['dateAndTimeOfDeath', 'causeOfDeath'] },
{ id: 'relationships', name: 'Relationships', fields: [] },
];

// These fields are handled specially in field.component.tsx
export const builtInFields = ['name', 'gender', 'dob', 'id', 'address', 'phone'] as const;
export const builtInFields = [
'name',
'gender',
'dob',
'id',
'address',
'phone',
'causeOfDeath',
'dateAndTimeOfDeath',
] as const;

export const esmPatientRegistrationSchema = {
sections: {
Expand Down Expand Up @@ -199,6 +213,14 @@ export const esmPatientRegistrationSchema = {
'Definitions for custom fields that can be used in sectionDefinitions. Can also be used to override built-in fields.',
},
fieldConfigurations: {
causeOfDeath: {
conceptUuid: {
_type: Type.ConceptUuid,
_description: 'The concept UUID to get cause of death answers',
_default: '9272a14b-7260-4353-9e5b-5787b5dead9d',
},
required: { _type: Type.Boolean, _default: false },
},
name: {
displayMiddleName: { _type: Type.Boolean, _default: true },
allowUnidentifiedPatients: {
Expand Down Expand Up @@ -359,6 +381,10 @@ export const esmPatientRegistrationSchema = {
'The form UUID to associate with the registration encounter. By default no form will be associated.',
},
},
freeTextFieldConceptUuid: {
_default: '5622AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
_type: Type.ConceptUuid,
},
_validators: [
validator(
(config: RegistrationConfig) =>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import React, { useMemo } from 'react';
import classNames from 'classnames';
import { Field, useField } from 'formik';
import { useTranslation } from 'react-i18next';
import { InlineNotification, Layer, Select, SelectItem, SelectSkeleton, TextInput } from '@carbon/react';
import { useConfig } from '@openmrs/esm-framework';
import { type RegistrationConfig } from '../../../config-schema';
import { useConceptAnswers } from '../field.resource';
import styles from '../field.scss';

export const CauseOfDeathField: React.FC = () => {
const { t } = useTranslation();
const { fieldConfigurations, freeTextFieldConceptUuid } = useConfig<RegistrationConfig>();
const [deathCause, deathCauseMeta] = useField('deathCause');

const conceptUuid = fieldConfigurations?.causeOfDeath?.conceptUuid;
const required = fieldConfigurations?.causeOfDeath?.required;

const {
data: conceptAnswers,
isLoading: isLoadingConceptAnswers,
error: errorLoadingConceptAnswers,
} = useConceptAnswers(conceptUuid);

const answers = useMemo(() => {
if (!isLoadingConceptAnswers && conceptAnswers) {
return conceptAnswers.map((answer) => ({ ...answer, label: answer.display }));
}
return [];
}, [conceptAnswers, isLoadingConceptAnswers]);

if (isLoadingConceptAnswers) {
return (
<div className={classNames(styles.customField, styles.halfWidthInDesktopView)}>
<h4 className={styles.productiveHeading02Light}>{t('causeOfDeathInputLabel', 'Cause of death')}</h4>
<SelectSkeleton />
</div>
);
}

return (
<div className={classNames(styles.customField, styles.halfWidthInDesktopView)}>
<h4 className={styles.productiveHeading02Light}>{t('causeOfDeathInputLabel', 'Cause of death')}</h4>
{errorLoadingConceptAnswers || !conceptUuid ? (
<InlineNotification
hideCloseButton
kind="error"
title={t('errorFetchingCodedCausesOfDeath', 'Error fetching coded causes of death')}
subtitle={t('refreshOrContactAdmin', 'Try refreshing the page or contact your system administrator')}
/>
) : (
<>
<Field name="deathCause">
{({ field, form: { touched, errors }, meta }) => {
return (
<Layer>
<Select
{...field}
id="deathCause"
invalid={errors.deathCause && touched.deathCause}
invalidText={errors.deathCause?.message}
labelText={t('causeOfDeathInputLabel', 'Cause of Death')}
name="deathCause"
required={required}>
<SelectItem id="empty-default-option" value={null} text={t('selectAnOption', 'Select an option')} />
{answers.map((answer) => (
<SelectItem id={answer.uuid} key={answer.uuid} text={answer.label} value={answer.uuid} />
))}
</Select>
</Layer>
);
}}
</Field>
{deathCause.value === freeTextFieldConceptUuid && (
<div className={styles.nonCodedCauseOfDeath}>
<Field name="nonCodedCauseOfDeath">
{({ field, form: { touched, errors }, meta }) => {
return (
<Layer>
<TextInput
{...field}
id="nonCodedCauseOfDeath"
invalid={errors?.nonCodedCauseOfDeath && touched.nonCodedCauseOfDeath}
invalidText={errors?.nonCodedCauseOfDeath?.message}
labelText={t('nonCodedCauseOfDeath', 'Non-coded cause of death')}
placeholder={t('enterNonCodedCauseOfDeath', 'Enter non-coded cause of death')}
/>
</Layer>
);
}}
</Field>
</div>
)}
</>
)}
</div>
);
};
Loading

0 comments on commit 82d3d9d

Please sign in to comment.