Skip to content

Commit 5f809f4

Browse files
committed
feat: Add filterlist to PatientList
1 parent 747cb40 commit 5f809f4

File tree

13 files changed

+150
-24
lines changed

13 files changed

+150
-24
lines changed

web/components/tables/PatientList.tsx

Lines changed: 71 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { useMemo, useState, forwardRef, useImperativeHandle, useEffect, useCallback, useRef } from 'react'
2-
import { Chip, FillerCell, HelpwaveLogo, LoadingContainer, SearchBar, ProgressIndicator, Tooltip, Drawer, TableProvider, TableDisplay, TableColumnSwitcher, TablePagination, IconButton, useLocale } from '@helpwave/hightide'
2+
import type { IdentifierFilterValue, FilterListItem, FilterListPopUpBuilderProps } from '@helpwave/hightide'
3+
import { Chip, FillerCell, HelpwaveLogo, LoadingContainer, SearchBar, ProgressIndicator, Tooltip, Drawer, TableProvider, TableDisplay, TableColumnSwitcher, TablePagination, IconButton, useLocale, FilterList } from '@helpwave/hightide'
34
import { PlusIcon } from 'lucide-react'
4-
import { Sex, PatientState, type GetPatientsQuery, type TaskType, PropertyEntity, type FullTextSearchInput, type LocationType } from '@/api/gql/generated'
5+
import type { LocationType } from '@/api/gql/generated'
6+
import { Sex, PatientState, type GetPatientsQuery, type TaskType, PropertyEntity, type FullTextSearchInput, FieldType } from '@/api/gql/generated'
57
import { usePropertyDefinitions, usePatientsPaginated, useRefreshingEntityIds } from '@/data'
68
import { PatientDetailView } from '@/components/patients/PatientDetailView'
79
import { LocationChips } from '@/components/locations/LocationChips'
@@ -15,6 +17,8 @@ import { getPropertyColumnsForEntity } from '@/utils/propertyColumn'
1517
import { useStorageSyncedTableState } from '@/hooks/useTableState'
1618
import { usePropertyColumnVisibility } from '@/hooks/usePropertyColumnVisibility'
1719
import { columnFiltersToFilterInput, paginationStateToPaginationInput, sortingStateToSortInput } from '@/utils/tableStateToApi'
20+
import { getPropertyFilterFn as getPropertyDatatype } from '@/utils/propertyFilterMapping'
21+
import { UserSelectFilterPopUp } from './UserSelectFilterPopUp'
1822

1923
export type PatientViewModel = {
2024
id: string,
@@ -190,7 +194,7 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
190194
}
191195

192196
const patientPropertyColumns = useMemo<ColumnDef<PatientViewModel>[]>(
193-
() => getPropertyColumnsForEntity<PatientViewModel>(propertyDefinitionsData, PropertyEntity.Patient),
197+
() => getPropertyColumnsForEntity<PatientViewModel>(propertyDefinitionsData, PropertyEntity.Patient, false),
194198
[propertyDefinitionsData]
195199
)
196200

@@ -211,7 +215,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
211215
minSize: 200,
212216
size: 250,
213217
maxSize: 300,
214-
filterFn: 'text',
215218
},
216219
{
217220
id: 'state',
@@ -229,7 +232,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
229232
minSize: 120,
230233
size: 144,
231234
maxSize: 180,
232-
filterFn: 'singleTag',
233235
meta: {
234236
filterData: {
235237
tags: allPatientStates.map(state => ({ label: translation('patientState', { state: state as string }), tag: state })),
@@ -272,7 +274,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
272274
minSize: 160,
273275
size: 160,
274276
maxSize: 200,
275-
filterFn: 'singleTag',
276277
meta: {
277278
filterData: {
278279
tags: [
@@ -299,7 +300,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
299300
minSize: 200,
300301
size: 260,
301302
maxSize: 320,
302-
filterFn: 'text' as const,
303303
},
304304
...(['CLINIC', 'WARD', 'ROOM', 'BED'] as const).map((kind): ColumnDef<PatientViewModel> => ({
305305
id: `location-${kind}`,
@@ -322,7 +322,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
322322
minSize: 160,
323323
size: 220,
324324
maxSize: 300,
325-
filterFn: 'text' as const,
326325
})),
327326
{
328327
id: 'birthdate',
@@ -351,7 +350,6 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
351350
minSize: 200,
352351
size: 200,
353352
maxSize: 200,
354-
filterFn: 'date' as const,
355353
},
356354
{
357355
id: 'tasks',
@@ -395,6 +393,62 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
395393
})),
396394
], [translation, allPatientStates, patientPropertyColumns, refreshingPatientIds, rowLoadingCell, dateFormat])
397395

396+
const availableFilters: FilterListItem[] = useMemo(() => [
397+
{
398+
id: 'name',
399+
label: translation('name'),
400+
dataType: 'text',
401+
tags: [],
402+
},
403+
{
404+
id: 'state',
405+
label: translation('status'),
406+
dataType: 'singleTag',
407+
tags: allPatientStates.map(state => ({ label: translation('patientState', { state: state as string }), tag: state })),
408+
},
409+
{
410+
id: 'sex',
411+
label: translation('sex'),
412+
dataType: 'singleTag',
413+
tags: [
414+
{ label: translation('male'), tag: Sex.Male },
415+
{ label: translation('female'), tag: Sex.Female },
416+
{ label: translation('diverse'), tag: Sex.Unknown },
417+
],
418+
},
419+
...(['CLINIC', 'WARD', 'ROOM', 'BED'] as const).map((kind): FilterListItem => ({
420+
id: `location-${kind}`,
421+
label: translation(LOCATION_KIND_HEADERS[kind] as 'locationClinic' | 'locationWard' | 'locationRoom' | 'locationBed'),
422+
dataType: 'text',
423+
tags: [],
424+
})),
425+
{
426+
id: 'birthdate',
427+
label: translation('birthdate'),
428+
dataType: 'date',
429+
tags: [],
430+
},
431+
{
432+
id: 'tasks',
433+
label: translation('tasks'),
434+
dataType: 'number',
435+
tags: [],
436+
},
437+
...propertyDefinitionsData?.propertyDefinitions.map(def => {
438+
const dataType = getPropertyDatatype(def.fieldType)
439+
return {
440+
id: `property_${def.id}`,
441+
label: def.name,
442+
dataType,
443+
tags: def.options.map((opt, idx) => ({
444+
label: opt,
445+
tag: `${def.id}-opt-${idx}`,
446+
})),
447+
popUpBuilder: def.fieldType === FieldType.FieldTypeUser ? (props: FilterListPopUpBuilderProps) => (<UserSelectFilterPopUp {...props}/>) : undefined,
448+
}
449+
}) ?? [],
450+
], [allPatientStates, propertyDefinitionsData?.propertyDefinitions, translation])
451+
398452
const onRowClick = useCallback((row: Row<PatientViewModel>) => handleEdit(row.original), [handleEdit])
399453
const fillerRowCell = useCallback(() => (<FillerCell className="min-h-8" />), [])
400454

@@ -431,6 +485,14 @@ export const PatientList = forwardRef<PatientListRef, PatientListProps>(({ initi
431485
value={searchQuery}
432486
onChange={(e) => setSearchQuery(e.target.value)}
433487
onSearch={() => null}
488+
containerProps={{ className: 'max-w-80' }}
489+
/>
490+
<FilterList
491+
value={filters as IdentifierFilterValue[]}
492+
onValueChange={value => {
493+
setFilters(value)
494+
}}
495+
availableItems={availableFilters}
434496
/>
435497
<TableColumnSwitcher />
436498
</div>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { useTasksTranslation } from '@/i18n/useTasksTranslation'
2+
import { FilterBasePopUp, FilterOperatorUtils, Visibility, type FilterListPopUpBuilderProps } from '@helpwave/hightide'
3+
import { useId, useMemo } from 'react'
4+
import { AssigneeSelect } from '../tasks/AssigneeSelect'
5+
6+
7+
export const UserSelectFilterPopUp = ({ value, onValueChange, onRemove, name }: FilterListPopUpBuilderProps) => {
8+
const translation = useTasksTranslation()
9+
const id = useId()
10+
const ids = {
11+
select: `user-select-filter-${id}`,
12+
}
13+
14+
const operator = useMemo(() => {
15+
const suggestion = value?.operator ?? 'contains'
16+
if (!FilterOperatorUtils.typeCheck.tagsSingle(suggestion)) {
17+
return 'contains'
18+
}
19+
return suggestion
20+
}, [value])
21+
22+
const parameter = value?.parameter ?? {}
23+
24+
const needsParameterInput = operator !== 'isUndefined' && operator !== 'isNotUndefined'
25+
26+
return (
27+
<FilterBasePopUp
28+
name={name}
29+
operator={operator}
30+
onOperatorChange={(newOperator) => onValueChange({ dataType: 'singleTag', parameter, operator: newOperator })}
31+
onRemove={onRemove}
32+
allowedOperators={FilterOperatorUtils.operatorsByCategory.singleTag}
33+
hasValue={!!value}
34+
noParameterRequired={!needsParameterInput}
35+
>
36+
<Visibility isVisible={needsParameterInput}>
37+
<div className="flex-col-1">
38+
<label htmlFor={ids.select} className="typography-label-md">{translation('user')}</label>
39+
<AssigneeSelect
40+
value={parameter.singleOptionSearch as string ?? ''}
41+
onValueChanged={(newUserValue) => onValueChange({ ...value, parameter: { ...parameter, singleOptionSearch: newUserValue } })}
42+
onDialogClose={(newUserValue) => onValueChange({ ...value, parameter: { ...parameter, singleOptionSearch: newUserValue } })}
43+
onValueClear={() => onValueChange({ ...value, parameter: { ...parameter, singleOptionSearch: undefined } })}
44+
/>
45+
</div>
46+
</Visibility>
47+
</FilterBasePopUp>
48+
)
49+
}

web/i18n/translations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ export type TasksTranslationEntries = {
205205
'type': string,
206206
'updated': string,
207207
'url': string,
208+
'user': string,
208209
'userInformation': string,
209210
'users': string,
210211
'waitingForPatient': string,
@@ -508,6 +509,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
508509
'type': `Typ`,
509510
'updated': `Aktualisiert`,
510511
'url': `URL`,
512+
'user': `Benutzer`,
511513
'userInformation': `Benutzerinformationen`,
512514
'users': `Benutzer`,
513515
'waitingForPatient': `Warten auf Patient`,
@@ -809,6 +811,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
809811
'type': `Type`,
810812
'updated': `Updated`,
811813
'url': `URL`,
814+
'user': `User`,
812815
'userInformation': `User Information`,
813816
'users': `Users`,
814817
'waitingForPatient': `Waiting for patient`,
@@ -1109,6 +1112,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
11091112
'type': `Tipo`,
11101113
'updated': `Actualizado`,
11111114
'url': `URL`,
1115+
'user': `Usuario`,
11121116
'userInformation': `Información del usuario`,
11131117
'users': `Usuarios`,
11141118
'waitingForPatient': `En espera de paciente`,
@@ -1409,6 +1413,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
14091413
'type': `Type`,
14101414
'updated': `Mis à jour`,
14111415
'url': `URL`,
1416+
'user': `Utilisateur`,
14121417
'userInformation': `Informations utilisateur`,
14131418
'users': `Utilisateurs`,
14141419
'waitingForPatient': `En attente du patient`,
@@ -1712,6 +1717,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
17121717
'type': `Type`,
17131718
'updated': `Bijgewerkt`,
17141719
'url': `URL`,
1720+
'user': `Gebruiker`,
17151721
'userInformation': `Gebruikersinformatie`,
17161722
'users': `Gebruikers`,
17171723
'waitingForPatient': `Wachten op patiënt`,
@@ -2012,6 +2018,7 @@ export const tasksTranslation: Translation<TasksTranslationLocales, Partial<Task
20122018
'type': `Tipo`,
20132019
'updated': `Atualizado`,
20142020
'url': `URL`,
2021+
'user': `Usuário`,
20152022
'userInformation': `Informações do usuário`,
20162023
'users': `Usuários`,
20172024
'waitingForPatient': `Aguardando paciente`,

web/locales/de-DE.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
"totalPatients": "Gesamtpatienten",
276276
"type": "Typ",
277277
"updated": "Aktualisiert",
278+
"user": "Benutzer",
278279
"users": "Benutzer",
279280
"wards": "Stationen",
280281
"yes": "Ja",

web/locales/en-US.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,7 @@
275275
"totalPatients": "Total Patients",
276276
"type": "Type",
277277
"updated": "Updated",
278+
"user": "User",
278279
"users": "Users",
279280
"wards": "Wards",
280281
"yes": "Yes",

web/locales/es-ES.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
"totalPatients": "Total de pacientes",
166166
"type": "Tipo",
167167
"updated": "Actualizado",
168+
"user": "Usuario",
168169
"users": "Usuarios",
169170
"wards": "Plantas",
170171
"yes": "Sí",

web/locales/fr-FR.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
"totalPatients": "Total des patients",
166166
"type": "Type",
167167
"updated": "Mis à jour",
168+
"user": "Utilisateur",
168169
"users": "Utilisateurs",
169170
"wards": "Services",
170171
"yes": "Oui",

web/locales/nl-NL.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
"totalPatients": "Totaal patiënten",
166166
"type": "Type",
167167
"updated": "Bijgewerkt",
168+
"user": "Gebruiker",
168169
"users": "Gebruikers",
169170
"wards": "Afdelingen",
170171
"yes": "Ja",

web/locales/pt-BR.arb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,7 @@
165165
"totalPatients": "Total de pacientes",
166166
"type": "Tipo",
167167
"updated": "Atualizado",
168+
"user": "Usuário",
168169
"users": "Usuários",
169170
"wards": "Enfermarias",
170171
"yes": "Sim",

web/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)