Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update RoomOverview.tsx #1137

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions api-services/types/tasks/patient.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import type { TaskDTO, TaskMinimalDTO } from './task'

export const genders = ['male', 'female', 'diverse'] as const
export type Gender = typeof genders[number]

export type PatientMinimalDTO = {
id: string,
name: string
Expand Down
6 changes: 3 additions & 3 deletions lib/twind/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,9 @@ export const colors: Record<AppColor, ShadedColors> = {
'hw-label-blue': generateShadingColors({ 400: '#758ECE' }),
'hw-label-pink': generateShadingColors({ 400: '#CE75A0' }),
'hw-label-yellow': generateShadingColors({ 400: '#EA8E00' }),
'hw-male': generateShadingColors({ 400: '#2761EB' }),
'hw-female': generateShadingColors({ 400: '#EC666D' }),
'hw-diverse': generateShadingColors({ 400: '#BABABA' }),
'hw-male': generateShadingColors({ 50: '#F6FAFF', 100: '#CBE0FF', 200: '#CBE0FF', 400: '#2761EB' }),
'hw-female': generateShadingColors({ 50: '#FFF9F9', 100: '#FFDADD', 200: '#FFB8C3', 400: '#EC666D' }),
'hw-diverse': generateShadingColors({ 50: '#FBFBFB', 100: '#E4E4E4', 200: '#BABABA', 400: '#000000' }),
} as const

export const config = defineConfig({
Expand Down
47 changes: 39 additions & 8 deletions tasks/components/RoomOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,57 @@ import { Span } from '@helpwave/common/components/Span'
import { useContext, useEffect, useRef, useState } from 'react'
import type { RoomOverviewDTO } from '@helpwave/api-services/types/tasks/room'
import type { BedMinimalDTO } from '@helpwave/api-services/types/tasks/bed'
import type { PatientDTO } from '@helpwave/api-services/types/tasks/patient'
import type { Gender, PatientDTO } from '@helpwave/api-services/types/tasks/patient'
import { emptyPatient } from '@helpwave/api-services/types/tasks/patient'
import type { AppColor } from '@helpwave/common/twind/config'
import type { Languages } from '@helpwave/common/hooks/useLanguage'
import type { PropsForTranslation } from '@helpwave/common/hooks/useTranslation'
import { useTranslation } from '@helpwave/common/hooks/useTranslation'
import { BedCard } from './cards/BedCard'
import { PatientCard } from './cards/PatientCard'
import { Droppable, Draggable } from './dnd-kit-instances/patients'
import { DragCard } from './cards/DragCard'
import { WardOverviewContext } from '@/pages/ward/[wardId]'

type RoomOverviewTranslation = Record<Gender, string>

const defaultRoomOverviewTranslations: Record<Languages, RoomOverviewTranslation> = {
en: {
male: 'M',
female: 'F',
diverse: 'D',
},
de: {
male: 'M',
female: 'F',
diverse: 'D',
}
}

export type RoomOverviewProps = {
room: RoomOverviewDTO
}

/**
* A component to show all beds and patients within a room in a ward
*/
export const RoomOverview = ({ room }: RoomOverviewProps) => {
export const RoomOverview = ({ room, overwriteTranslation }: PropsForTranslation<RoomOverviewTranslation, RoomOverviewProps>) => {
const translation = useTranslation(defaultRoomOverviewTranslations, overwriteTranslation)
const context = useContext(WardOverviewContext)
const ref = useRef<HTMLDivElement>(null)
const [columns, setColumns] = useState(3)

// const patients = room.beds.filter(value => value.patient !== null).map(value => value.patient!)
const gender: Gender | undefined = undefined
// TODO set gender according to patients

const genderColorMapping: Record<Gender, AppColor> = {
male: 'hw-male',
female: 'hw-female',
diverse: 'hw-diverse',
}
const usedColor = genderColorMapping[gender ?? 'diverse']

const setSelectedBed = (room: RoomOverviewDTO, bed: BedMinimalDTO, patientId?: string, patient?: PatientDTO) =>
context.updateContext({
...context.state,
Expand All @@ -43,8 +74,11 @@ export const RoomOverview = ({ room }: RoomOverviewProps) => {
return (
<div className={tw('flex flex-col w-full')} ref={ref}>
<div className={tw('flex flex-row items-center mb-1')}>
<div className={tw('w-2 h-2 mx-2 rounded-full bg-gray-300')}/>
<Span type="subsectionTitle">{room.name}</Span>
<div className={tw(`w-3 h-3 mx-2 rounded-full bg-${usedColor}-400`)}/>
<div className={tw('flex flex-row items-center gap-x-2')}>
<Span type="subsectionTitle">{room.name}</Span>
{gender && <Span type="description" className="text-sm font-semibold">({translation[gender]})</Span>}
</div>
</div>
<div className={tw(`grid grid-cols-${columns} gap-4`)}>
{room.beds.map((bed) => bed.patient && bed.patient?.id ?
Expand All @@ -59,13 +93,10 @@ export const RoomOverview = ({ room }: RoomOverviewProps) => {
<PatientCard
bedName={bed.name}
patientName={bed.patient.name}
doneTasks={bed.patient.tasksDone}
inProgressTasks={bed.patient.tasksInProgress}
unscheduledTasks={bed.patient.tasksUnscheduled}
openTasks={bed.patient.tasksUnscheduled}
onTileClick={(event) => {
event.stopPropagation()
if (bed.patient) {
// LINTER: `bed.patient.id` gets evaluated as undefined without this if
setSelectedBed(room, bed, bed.patient.id)
}
}}
Expand Down
35 changes: 28 additions & 7 deletions tasks/components/cards/DragCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,30 @@ import type { PropsWithChildren } from 'react'
import { tx } from '@helpwave/common/twind'
import { Card, type CardProps } from '@helpwave/common/components/Card'

export type DragCardStyle = {
normal: string,
selected: string,
dragged: string,
dragOverNormal: string,
dragOverDangerous: string,
dragOverInvalid: string
}

const defaultDragCardStyle: DragCardStyle = {
normal: 'hover:border-hw-primary-800',
selected: 'border-hw-primary-700',
dragged: '',
dragOverDangerous: 'border-hw-warn-400 border-dashed',
dragOverNormal: 'border-hw-primary-700 border-dashed',
dragOverInvalid: 'border-hw-negative-400'
}

export type CardDragProperties = {
isDragging?: boolean,
isOver?: boolean,
isDangerous?: boolean,
isInvalid?: boolean
isInvalid?: boolean,
styleOverwrite?: Partial<DragCardStyle>
}

export type DragCardProps = PropsWithChildren<CardProps & {
Expand All @@ -23,15 +42,17 @@ export const DragCard = ({
className,
...cardProps
}: DragCardProps) => {
const style: DragCardStyle = { ...cardDragProperties?.styleOverwrite, ...defaultDragCardStyle }

// For now fully equal to a normal card but, that might change later
return (
<Card className={tx(className, 'border-2', {
'hover:border-hw-primary-800 cursor-pointer': !cardDragProperties.isDragging && !cardDragProperties.isOver, // default
'border-hw-primary-700': isSelected,
'cursor-grabbing': cardDragProperties.isDragging,
'border-hw-warn-400 border-dashed': cardDragProperties.isOver && cardDragProperties.isDangerous,
'border-hw-primary-700 border-dashed': cardDragProperties.isOver && !cardDragProperties.isDangerous && !cardDragProperties.isInvalid,
'border-hw-negative-400': cardDragProperties.isOver && cardDragProperties.isInvalid,
[`${style.normal} cursor-pointer`]: !cardDragProperties.isDragging && !cardDragProperties.isOver, // default
[style.selected]: isSelected,
[`cursor-grabbing ${style.dragged}`]: cardDragProperties.isDragging,
[style.dragOverDangerous]: cardDragProperties.isOver && cardDragProperties.isDangerous,
[style.dragOverNormal]: cardDragProperties.isOver && !cardDragProperties.isDangerous && !cardDragProperties.isInvalid,
[style.dragOverInvalid]: cardDragProperties.isOver && cardDragProperties.isInvalid,
})} {...cardProps}>
{children}
</Card>
Expand Down
73 changes: 51 additions & 22 deletions tasks/components/cards/PatientCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,45 @@ import { tw } from '@helpwave/common/twind'
import { Span } from '@helpwave/common/components/Span'
import type { Languages } from '@helpwave/common/hooks/useLanguage'
import { useTranslation, type PropsForTranslation } from '@helpwave/common/hooks/useTranslation'
import { PillLabelsColumn } from '../pill/PillLabelsColumn'
import { DragCard, type DragCardProps } from './DragCard'
import type { Gender } from '@helpwave/api-services/types/tasks/patient'
import { Check, TriangleAlert } from 'lucide-react'
import type { AppColor } from '@helpwave/common/twind/config'
import { tx } from '@twind/core'
import { Card } from '@helpwave/common/components/Card'
import type { DragCardProps } from '@/components/cards/DragCard'

type PatientCardTranslation = {
bedNotAssigned: string
}
bedNotAssigned: string,
years: string,
openTasks: (amount: number) => string
} & Record<Gender, string>

const defaultPatientCardTranslations: Record<Languages, PatientCardTranslation> = {
en: {
bedNotAssigned: 'Not Assigned',
years: 'yrs',
male: 'M',
female: 'F',
diverse: 'D',
openTasks: amount => amount === 1 ? `${amount} Open Task` : `${amount} Open Tasks`
},
de: {
bedNotAssigned: 'Nicht Zugewiesen',
years: 'jr',
male: 'M',
female: 'F',
diverse: 'D',
openTasks: amount => amount === 1 ? `${amount} Offener Task` : `${amount} Offene Tasks`
}
}

export type PatientCardProps = DragCardProps & {
bedName?: string,
patientName: string,
unscheduledTasks?: number,
inProgressTasks?: number,
doneTasks?: number
openTasks?: number,
gender?: Gender,
age?: number,
hasWarning?: boolean
}

/**
Expand All @@ -33,27 +50,39 @@ export const PatientCard = ({
overwriteTranslation,
bedName,
patientName,
unscheduledTasks,
inProgressTasks,
doneTasks,
openTasks = 0,
gender = 'diverse', // TODO change to required when patient has this property
hasWarning = false,
age = 32, // TODO change to required when patient has this property
isSelected,
onTileClick,
className,
...restCardProps
}: PropsForTranslation<PatientCardTranslation, PatientCardProps>) => {
const translation = useTranslation(defaultPatientCardTranslations, overwriteTranslation)
const genderColorMapping: Record<Gender, AppColor> = {
male: 'hw-male',
female: 'hw-female',
diverse: 'hw-diverse',
}

const usedColor = genderColorMapping[gender]

return (
<DragCard isSelected={isSelected} onTileClick={onTileClick} {...restCardProps}>
<div className={tw('flex flex-row justify-between')}>
<Span className={tw('whitespace-nowrap')} type="subsubsectionTitle">{bedName ?? translation.bedNotAssigned}</Span>
<Span className={tw('ml-2 truncate')}>{patientName}</Span>
<Card isSelected={isSelected} {...restCardProps} className={tx(`flex flex-col !border-${usedColor}-200 hover:!border-${usedColor}-400 !bg-${usedColor}-50 gap-y-1 py-3`, className)} >
<div className={tw('flex flex-row justify-between gap-x-2 items-center')}>
<Span type="description" className={tw('font-semibold')}>{bedName ?? translation.bedNotAssigned}</Span>
{hasWarning && <TriangleAlert className={tw('text-hw-warn-400')} />}
</div>
<div className={tw('flex flex-row justify-between gap-x-2 items-center')}>
<Span className={tw('truncate font-bold text-lg')}>{patientName}</Span>
<Span type="description">{translation[gender]},<Span type="description" className="font-semibold">{age}</Span>{`${translation.years}`}</Span>
</div>
<div className={tw('min-w-[150px] max-w-[200px] mt-1')}>
<PillLabelsColumn
doneCount={doneTasks}
inProgressCount={inProgressTasks}
unscheduledCount={unscheduledTasks}
/>
<div className={tx(`flex flex-row gap-x-2 text-${usedColor}-400 items-center`, { 'opacity-40': openTasks === 0 })}>
<div className={tw(`p-[2px] rounded-full bg-${usedColor}-100`)}>
<Check size={16} strokeWidth={2}/>
</div>
<Span className={tw('font-semibold')}>{translation.openTasks(openTasks)}</Span>
</div>
</DragCard>
</Card>
)
}
19 changes: 11 additions & 8 deletions tasks/components/layout/WardRoomList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,20 +88,23 @@ export const WardRoomList = ({
isLoading={isLoading}
hasError={isError}
>
{displayableRooms.length > 0 ?
displayableRooms.map(room => (
<RoomOverview
key={room.id}
room={room}
/>
)) : (
{displayableRooms.length > 0 ? (
<div className={tw('flex flex-col gap-y-4')}>
{displayableRooms.map(room => (
<RoomOverview
key={room.id}
room={room}
/>
))}
</div>
) : (
<div className={tw('flex flex-col gap-y-2 items-center')}>
<Span>{translation.noRooms}</Span>
<Link href={`/organizations/${organization?.id ?? ''}?wardId=${contextState.wardId}`}>
<Button>{translation.editWard}</Button>
</Link>
</div>
)}
)}
</LoadingAndErrorComponent>
</div>
)
Expand Down
4 changes: 1 addition & 3 deletions tasks/pages/ward/[wardId].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -333,9 +333,7 @@ const WardOverview: NextPage = ({ overwriteTranslation }: PropsForTranslation<Wa
<PatientCard
bedName={draggedPatient.bed.name}
patientName={draggedPatient.bed.patient.name}
unscheduledTasks={draggedPatient.bed.patient.tasksUnscheduled}
inProgressTasks={draggedPatient.bed.patient.tasksInProgress}
doneTasks={draggedPatient.bed.patient.tasksDone}
openTasks={draggedPatient.bed.patient.tasksUnscheduled}
/>
)
)}
Expand Down
Loading