Skip to content

Commit

Permalink
feat: add patientlist backend connection
Browse files Browse the repository at this point in the history
  • Loading branch information
DasProffi authored Aug 13, 2023
1 parent 59420ba commit d5a36d7
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 97 deletions.
44 changes: 44 additions & 0 deletions lib/components/HideableContentSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { tw, tx } from '../twind'
import type { PropsWithChildren } from 'react'
import { ChevronDown, ChevronUp } from 'lucide-react'
import React, { useState } from 'react'

export type HideableContentSectionProps = PropsWithChildren & {
initiallyOpen?: boolean,
disabled: boolean,
header: React.ReactNode
}

/**
* A Component to hide and show
*/
export const HideableContentSection = ({
initiallyOpen = true,
disabled,
children,
header
}: HideableContentSectionProps) => {
const [open, setOpen] = useState(initiallyOpen)
return (
<div className={tw('flex flex-col gap-y-2')}>
<div
className={tx('flex flex-row justify-between items-center', { 'cursor-pointer': !disabled })}
onClick={() => {
if (!disabled) {
setOpen(!open)
}
}}
>
<div>
{header}
</div>
{!disabled && (open ? <ChevronUp/> : <ChevronDown/>)}
</div>
{open && (
<div>
{children}
</div>
)}
</div>
)
}
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tasks/components/layout/PatientDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export const PatientDetail = ({
onBackgroundClick={() => setIsShowingDischargeDialog(false)}
onConfirm={() => {
setIsShowingDischargeDialog(false)
dischargeMutation.mutate(newPatient)
dischargeMutation.mutate(newPatient.id)
}}
confirmType="negative"
/>
Expand Down
163 changes: 95 additions & 68 deletions tasks/components/layout/PatientList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ import { tw } from '@helpwave/common/twind'
import type { Languages } from '@helpwave/common/hooks/useLanguage'
import type { PropsWithLanguage } from '@helpwave/common/hooks/useTranslation'
import { useTranslation } from '@helpwave/common/hooks/useTranslation'
import React, { useContext, useState } from 'react'
import React, { useState } from 'react'
import { Button } from '@helpwave/common/components/Button'
import { Span } from '@helpwave/common/components/Span'
import { Input } from '@helpwave/common/components/user_input/Input'
import type { PatientDTO, PatientWithBedAndRoomDTO } from '../../mutations/patient_mutations'
import { usePatientListQuery } from '../../mutations/patient_mutations'
import { usePatientDischargeMutation, usePatientListQuery } from '../../mutations/patient_mutations'
import { Label } from '../Label'
import { MultiSearchWithMapping, SimpleSearchWithMapping } from '../../utils/simpleSearch'
import { WardOverviewContext } from '../../pages/ward/[uuid]'
import { LoadingAndErrorComponent } from '@helpwave/common/components/LoadingAndErrorComponent'
import { HideableContentSection } from '@helpwave/common/components/HideableContentSection'

type PatientListTranslation = {
patients: string,
Expand Down Expand Up @@ -58,39 +59,45 @@ const defaultPatientListTranslations: Record<Languages, PatientListTranslation>
}
}

export type PatientListOpenedSectionsType = {
active: boolean,
unassigned: boolean,
discharged: boolean
}

export const defaultPatientListOpenedSections: PatientListOpenedSectionsType = {
active: true,
unassigned: true,
discharged: false
}

export type PatientListProps = {
onDischarge?: (patient: PatientDTO) => void,
initialOpenedSections?:PatientListOpenedSectionsType,
width?: number
}

/**
* The right side of the ward/[uuid].tsx page showing the detailed information about the patients in the ward
*/
export const PatientList = ({
language
language,
initialOpenedSections = defaultPatientListOpenedSections
}: PropsWithLanguage<PatientListTranslation, PatientListProps>) => {
const translation = useTranslation(language, defaultPatientListTranslations)
const [search, setSearch] = useState('')
const context = useContext(WardOverviewContext)
const { data, isLoading, isError } = usePatientListQuery(context.state.wardID)

if (isError) {
return <p>Error</p>
}

if (isLoading || !data) {
return null
}
const { data, isLoading, isError } = usePatientListQuery()
const dischargeMutation = usePatientDischargeMutation()

const activeLabelText = (patient: PatientWithBedAndRoomDTO) => `${patient.room.name} - ${patient.bed.name}`

const filteredActive = MultiSearchWithMapping(search, data.active, value => [value.name, activeLabelText(value)])
const filteredUnassigned = SimpleSearchWithMapping(search, data.unassigned, value => value.name)
const filteredDischarged = SimpleSearchWithMapping(search, data.discharged, value => value.name)
const filteredActive = !data ? [] : MultiSearchWithMapping(search, data.active, value => [value.name, activeLabelText(value)])
const filteredUnassigned = !data ? [] : SimpleSearchWithMapping(search, data.unassigned, value => value.name)
const filteredDischarged = !data ? [] : SimpleSearchWithMapping(search, data.discharged, value => value.name)

return (
<div className={tw('relative flex flex-col py-4 px-6')}>
<div className={tw('flex flex-row gap-x-2 items-center')}>
<div className={tw('flex flex-row gap-x-2 items-center mb-6')}>
<Span type="subsectionTitle" className={tw('pr-4')}>{translation.patients}</Span>
<Input placeholder={translation.search} value={search} onChange={setSearch} className={tw('h-9')}/>
<Button
Expand All @@ -103,57 +110,77 @@ export const PatientList = ({
{translation.addPatient}
</Button>
</div>
{filteredActive.length >= 0 && (
<div className={tw('flex flex-col mt-6')}>
<Span type="accent">{`${translation.active} (${filteredActive.length})`}</Span>
{filteredActive.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 justify-between items-center')}>
<Span className={tw('font-space font-bold w-1/3 text-ellipsis')}>{patient.name}</Span>
<div className={tw('flex flex-row flex-1 justify-between items-center')}>
<Label name={activeLabelText(patient)} color="blue"/>
<Button color="negative" variant="textButton" onClick={() => {
// TODO discharge
}}>
{translation.discharge}
</Button>
</div>
</div>
))}
</div>
)}
{filteredUnassigned.length >= 0 && (
<div className={tw('flex flex-col mt-6')}>
<Span type="accent" className={tw('text-hw-label-yellow-text')}>{`${translation.unassigned} (${filteredUnassigned.length})`}</Span>
{filteredUnassigned.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 items-center')}>
<Span className={tw('font-space font-bold w-1/3 text-ellipsis')}>{patient.name}</Span>
<div className={tw('flex flex-row flex-1 justify-between items-center')}>
<Label name={`${translation.unassigned}`} color="yellow"/>
<Button color="negative" variant="textButton" onClick={() => {
// TODO discharge
}}>
{translation.discharge}
</Button>
</div>
</div>
))}
</div>
)}
{filteredDischarged.length >= 0 && (
<div className={tw('flex flex-col mt-6')}>
<Span type="accent">{`${translation.discharged} (${filteredDischarged.length})`}</Span>
{filteredDischarged.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 justify-between items-center')}>
<Span className={tw('font-space font-bold')}>{patient.name}</Span>
<Button color="negative" variant="textButton" onClick={() => {
// TODO delete
}}>
{translation.delete}
</Button>
</div>
))}
<LoadingAndErrorComponent
hasError={isError || !data}
isLoading={isLoading}
errorProps={{ classname: tw('min-h-[400px] border-2 border-gray-600 rounded-xl') }}
loadingProps={{ classname: tw('min-h-[400px] border-2 border-gray-600 rounded-xl') }}
>
<div className={tw('flex flex-col gap-y-4 mb-8')}>
{filteredActive.length >= 0 && (
<HideableContentSection
initiallyOpen={initialOpenedSections?.active}
disabled={filteredActive.length <= 0}
header={<Span type="accent">{`${translation.active} (${filteredActive.length})`}</Span>}
>
{filteredActive.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 justify-between items-center')}>
<Span className={tw('font-space font-bold w-1/3 text-ellipsis')}>{patient.name}</Span>
<div className={tw('flex flex-row flex-1 justify-between items-center')}>
<Label name={activeLabelText(patient)} color="blue"/>
<Button color="negative" variant="textButton" onClick={() => {
dischargeMutation.mutate(patient.id)
}}>
{translation.discharge}
</Button>
</div>
</div>
))}
</HideableContentSection>
)}
{filteredUnassigned.length >= 0 && (
<HideableContentSection
initiallyOpen={initialOpenedSections?.unassigned}
disabled={filteredUnassigned.length <= 0}
header={ <Span type="accent" className={tw('text-hw-label-yellow-text')}>{`${translation.unassigned} (${filteredUnassigned.length})`}</Span>}
>
{filteredUnassigned.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 items-center')}>
<Span className={tw('font-space font-bold w-1/3 text-ellipsis')}>{patient.name}</Span>
<div className={tw('flex flex-row flex-1 justify-between items-center')}>
<Label name={`${translation.unassigned}`} color="yellow"/>
<Button color="negative" variant="textButton" onClick={() => {
dischargeMutation.mutate(patient.id)
}}>
{translation.discharge}
</Button>
</div>
</div>
))}
</HideableContentSection>
)}
{filteredDischarged.length >= 0 && (
<HideableContentSection
initiallyOpen={initialOpenedSections?.discharged}
disabled={filteredDischarged.length <= 0}
header={<Span type="accent">{`${translation.discharged} (${filteredDischarged.length})`}</Span>}
>
{filteredDischarged.map(patient => (
<div key={patient.id} className={tw('flex flex-row pt-2 border-b-2 justify-between items-center')}>
<Span className={tw('font-space font-bold')}>{patient.name}</Span>
{ /* TODO implement when backend endpoint exists
<Button color="negative" variant="textButton" onClick={() => {
// TODO delete
}}>
{translation.delete}
</Button>
*/}
</div>
))}
</HideableContentSection>
)}
</div>
)}
</LoadingAndErrorComponent>
</div>
)
}
Loading

0 comments on commit d5a36d7

Please sign in to comment.