diff --git a/packages/esm-patient-forms-app/src/forms/form-view.component.tsx b/packages/esm-patient-forms-app/src/forms/form-view.component.tsx index 8a9ef56246..0052eff810 100644 --- a/packages/esm-patient-forms-app/src/forms/form-view.component.tsx +++ b/packages/esm-patient-forms-app/src/forms/form-view.component.tsx @@ -1,14 +1,11 @@ -import React, { useState, useEffect, useMemo } from 'react'; +import React, { useMemo } from 'react'; import { useTranslation } from 'react-i18next'; -import isEmpty from 'lodash-es/isEmpty'; import first from 'lodash-es/first'; -import debounce from 'lodash-es/debounce'; import { DataTable, DataTableHeader, DataTableRow, Layer, - Search, Table, TableBody, TableCell, @@ -16,17 +13,23 @@ import { TableHead, TableHeader, TableRow, + TableToolbar, + TableToolbarContent, + TableToolbarSearch, Tile, } from '@carbon/react'; import { Edit } from '@carbon/react/icons'; import { EmptyDataIllustration, PatientChartPagination, useVisitOrOfflineVisit } from '@openmrs/esm-patient-common-lib'; -import { isDesktop, formatDatetime, useConfig, useLayoutType, usePagination } from '@openmrs/esm-framework'; +import { formatDatetime, useConfig, usePagination } from '@openmrs/esm-framework'; import { ConfigObject } from '../config-schema'; import { CompletedFormInfo } from '../types'; import { launchFormEntryOrHtmlForms } from '../form-entry-interop'; import styles from './form-view.scss'; +type FormsCategory = 'All' | 'Completed' | 'Recommended'; + interface FormViewProps { + category?: FormsCategory; forms: Array; patientUuid: string; patient: fhir.Patient; @@ -35,28 +38,25 @@ interface FormViewProps { urlLabel: string; } -const FormView: React.FC = ({ forms, patientUuid, patient, pageSize, pageUrl, urlLabel }) => { +interface FilterProps { + rowIds: Array; + headers: Array>; + cellsById: any; + inputValue: string; + getCellId: (row, key) => string; +} + +const FormView: React.FC = ({ category, forms, patientUuid, patient, pageSize, pageUrl, urlLabel }) => { const { t } = useTranslation(); const config = useConfig() as ConfigObject; const htmlFormEntryForms = config.htmlFormEntryForms; - const layout = useLayoutType(); const { currentVisit } = useVisitOrOfflineVisit(patientUuid); - const [searchTerm, setSearchTerm] = useState(null); - const [allFormInfos, setAllFormInfos] = useState>(forms); + const { results, goTo, currentPage } = usePagination( - allFormInfos.sort((a, b) => (b.lastCompleted?.getTime() ?? 0) - (a.lastCompleted?.getTime() ?? 0)), + forms?.sort((a, b) => (b.lastCompleted?.getTime() ?? 0) - (a.lastCompleted?.getTime() ?? 0)), pageSize, ); - const handleSearch = useMemo(() => debounce((searchTerm) => setSearchTerm(searchTerm), 300), []); - - useEffect(() => { - const entriesToDisplay = isEmpty(searchTerm) - ? forms - : forms.filter((formInfo) => formInfo.form.name.toLowerCase().search(searchTerm?.toLowerCase()) !== -1); - setAllFormInfos(entriesToDisplay); - }, [searchTerm, forms]); - const tableHeaders: Array = useMemo( () => [ { @@ -82,54 +82,82 @@ const FormView: React.FC = ({ forms, patientUuid, patient, pageSi [results], ); + const handleFilter = ({ rowIds, headers, cellsById, inputValue, getCellId }: FilterProps): Array => { + return rowIds.filter((rowId) => + headers.some(({ key }) => { + const cellId = getCellId(rowId, key); + const filterableValue = cellsById[cellId].value; + const filterTerm = inputValue.toLowerCase(); + + return ('' + filterableValue).toLowerCase().includes(filterTerm); + }), + ); + }; + + if (!forms?.length) { + return ( + + + +

+ {t('noMatchingFormsAvailable', 'There are no {formCategory} forms to display', { + formCategory: category?.toLowerCase(), + })} +

+

{t('formSearchHint', 'Try using an alternative name or keyword')}

+
+
+ ); + } + return (
- handleSearch(e.target.value)} - /> - <> - {searchTerm?.length > 0 && allFormInfos?.length > 0 && ( -

- {allFormInfos.length} {t('matchesFound', 'match(es) found')} -

- )} - {allFormInfos?.length > 0 && ( - <> - - {({ rows, headers, getHeaderProps, getTableProps }) => ( - - - - - {headers.map((header) => ( - - {header.header?.content ?? header.header} - - ))} - - - - {rows.map((row, index) => { - return ( - - {row.cells[0].value ?? t('never', 'Never')} - + {forms?.length > 0 && ( + <> + + {({ rows, headers, getHeaderProps, getTableProps, onInputChange }) => ( + + + + + + +
+ + + {headers.map((header) => ( + + {header.header} + + ))} + + + + {rows.map((row, index) => { + return ( + + {row.cells[0].value ?? t('never', 'Never')} + +
-
- )} -
- goTo(page)} - dashboardLinkUrl={pageUrl} - dashboardLinkLabel={urlLabel} - /> - - )} - {isEmpty(allFormInfos) ? ( - - - -

{t('noFormsAvailable', 'There are no matching forms to display')}

-

- {t('formSearchHint', 'Try searching for the form using an alternative name or keyword')} -

-
-
- ) : null} - +
+ + + ); + })} + + + {rows.length === 0 ? ( +
+ +
+

+ {t('noMatchingFormsToDisplay', 'No matching forms to display')} +

+
+
+
+ ) : null} + + )} + + goTo(page)} + dashboardLinkUrl={pageUrl} + dashboardLinkLabel={urlLabel} + /> + + )} ); }; diff --git a/packages/esm-patient-forms-app/src/forms/form-view.scss b/packages/esm-patient-forms-app/src/forms/form-view.scss index 2364173aa1..7059770263 100644 --- a/packages/esm-patient-forms-app/src/forms/form-view.scss +++ b/packages/esm-patient-forms-app/src/forms/form-view.scss @@ -3,10 +3,14 @@ @import '~@openmrs/esm-styleguide/src/vars'; @import '../root.scss'; -.productiveHeading01 { +.heading { @include type.type-style("heading-compact-01"); } +.text02 { + color: $text-02; +} + .bodyShort01 { @include type.type-style("body-compact-01"); } @@ -31,7 +35,29 @@ } .formResultsLabel { + @include type.type-style('body-compact-01'); margin: spacing.$spacing-05; + color: $text-02; +} + +.table { + margin-top: 3rem; +} + +.tileContainer { + background-color: $ui-02; + margin: 3rem; +} + +.tile { + margin: auto; + width: fit-content; +} + +.tileContent { + display: flex; + flex-direction: column; + align-items: center; } // Desktop viewport @@ -68,7 +94,6 @@ height: spacing.$spacing-09; align-items: center; - & > label { cursor: pointer; } @@ -95,3 +120,10 @@ color: $color-gray-70; margin: 0.5rem 0; } + +.searchInput { + input:focus { + outline: none; + border: spacing.$spacing-01 solid var(--omrs-color-brand-orange); + } +} diff --git a/packages/esm-patient-forms-app/src/forms/forms.component.tsx b/packages/esm-patient-forms-app/src/forms/forms.component.tsx index 385ce96ae5..1b37bbae3d 100644 --- a/packages/esm-patient-forms-app/src/forms/forms.component.tsx +++ b/packages/esm-patient-forms-app/src/forms/forms.component.tsx @@ -14,11 +14,7 @@ import EmptyFormView from './empty-form.component'; import FormView from './form-view.component'; import styles from './forms.scss'; -const enum FormsCategory { - Recommended, - Completed, - All, -} +type FormsCategory = 'All' | 'Completed' | 'Recommended'; interface FormsProps { patientUuid: string; @@ -35,9 +31,7 @@ const Forms: React.FC = ({ patientUuid, patient, pageSize, pageUrl, const { htmlFormEntryForms, showRecommendedFormsTab, showConfigurableForms } = useConfig() as ConfigObject; const headerTitle = t('forms', 'Forms'); const isTablet = useLayoutType() === 'tablet'; - const [formsCategory, setFormsCategory] = useState( - showRecommendedFormsTab ? FormsCategory.Recommended : FormsCategory.All, - ); + const [formsCategory, setFormsCategory] = useState(showRecommendedFormsTab ? 'Recommended' : 'All'); const { isValidating, data, error } = useForms(patientUuid, undefined, undefined, isOffline); const session = useSession(); let formsToDisplay = isOffline @@ -49,6 +43,14 @@ const Forms: React.FC = ({ patientUuid, patient, pageSize, pageUrl, const { currentVisit } = useVisitOrOfflineVisit(patientUuid); const { programConfigs } = useProgramConfig(patientUuid, showRecommendedFormsTab); + const completedForms = useMemo( + () => + formsToDisplay?.filter( + ({ associatedEncounters, lastCompleted }) => associatedEncounters.length > 0 && dayjs(lastCompleted).isToday(), + ), + [formsToDisplay], + ); + const recommendedForms = useMemo( () => formsToDisplay @@ -104,19 +106,17 @@ const Forms: React.FC = ({ patientUuid, patient, pageSize, pageUrl, onChange={(event) => setFormsCategory(event.name as any)} selectedIndex={formsCategory} > - - - + + +
- {formsCategory === FormsCategory.Completed && ( + {formsCategory === 'Completed' && ( - associatedEncounters.length > 0 && dayjs(lastCompleted).isToday(), - )} + category={'Completed'} + forms={completedForms} patientUuid={patientUuid} patient={patient} pageSize={pageSize} @@ -124,7 +124,7 @@ const Forms: React.FC = ({ patientUuid, patient, pageSize, pageUrl, urlLabel={urlLabel} /> )} - {formsCategory === FormsCategory.All && ( + {formsCategory === 'All' && ( = ({ patientUuid, patient, pageSize, pageUrl, urlLabel={urlLabel} /> )} - {formsCategory === FormsCategory.Recommended && ( + {formsCategory === 'Recommended' && (