Skip to content
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
44 changes: 19 additions & 25 deletions web/components/Notifications.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useEffect, useMemo } from 'react'
import { Button, Chip, PopUp, PopUpContext, PopUpOpener, PopUpRoot, Tooltip, useLocalStorage, Visibility } from '@helpwave/hightide'
import { Button, Chip, IconButton, PopUp, PopUpContext, PopUpOpener, PopUpRoot, useStorage, Visibility } from '@helpwave/hightide'
import { Bell } from 'lucide-react'
import { useOverviewData } from '@/data'
import { useTasksTranslation } from '@/i18n/useTasksTranslation'
Expand All @@ -26,12 +26,12 @@ export const Notifications = () => {
const {
value: readNotificationsRaw,
setValue: setReadNotificationsRaw
} = useLocalStorage<string[]>('read-notifications', [])
} = useStorage<string[]>({ key: 'read-notifications', defaultValue: [] })

const {
value: dismissedNotificationsRaw,
setValue: setDismissedNotificationsRaw
} = useLocalStorage<string[]>('dismissed-notifications', [])
} = useStorage<string[]>({ key: 'dismissed-notifications', defaultValue: [] })

const readNotifications = useMemo(() => {
return new Set(readNotificationsRaw || [])
Expand Down Expand Up @@ -131,29 +131,23 @@ export const Notifications = () => {

return (
<PopUpRoot>
<PopUpContext.Consumer>
{({ isOpen }) => (
<Tooltip tooltip={translation('notifications')} disabled={isOpen}>
<PopUpOpener>
{({ props }) => (
<Button
{...props}
coloringStyle="text"
layout="icon"
color="neutral"
>
<Bell className="size-5" />
{unreadCount > 0 && (
<span className="absolute -top-0.5 -right-0.5 flex-row-0 min-w-4.5 h-4.5 items-center justify-center rounded-full bg-primary text-on-primary text-xs font-bold leading-none">
{unreadCount > 9 ? '9+' : unreadCount}
</span>
)}
</Button>
)}
</PopUpOpener>
</Tooltip>
<PopUpOpener>
{({ props }) => (
<IconButton
{...props}
tooltip={translation('notifications')}
coloringStyle="text"
color="neutral"
>
<Bell className="size-5" />
{unreadCount > 0 && (
<span className="absolute -top-0.5 -right-0.5 flex-row-0 min-w-4.5 h-4.5 items-center justify-center rounded-full bg-primary text-on-primary text-xs font-bold leading-none">
{unreadCount > 9 ? '9+' : unreadCount}
</span>
)}
</IconButton>
)}
</PopUpContext.Consumer>
</PopUpOpener>
<PopUp
options={{
horizontalAlignment: 'center'
Expand Down
48 changes: 27 additions & 21 deletions web/components/layout/Page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import {
ExpandableContent,
ExpandableHeader,
ExpandableRoot,
IconButton,
MarkdownInterpreter,
Tooltip,
useLocalStorage
useStorage
} from '@helpwave/hightide'
import { AvatarStatusComponent } from '@/components/AvatarStatusComponent'
import { getConfig } from '@/utils/config'
Expand Down Expand Up @@ -49,7 +50,7 @@ export const StagingDisclaimerDialog = () => {
const {
value: lastTimeStagingDisclaimerDismissed,
setValue: setLastTimeStagingDisclaimerDismissed
} = useLocalStorage('staging-disclaimer-dismissed-time', 0)
} = useStorage({ key: 'staging-disclaimer-dismissed-time', defaultValue: 0 })

const dismissStagingDisclaimer = () => {
setLastTimeStagingDisclaimerDismissed(new Date().getTime())
Expand Down Expand Up @@ -102,17 +103,17 @@ export const SurveyModal = () => {
const {
value: onboardingSurveyCompleted,
setValue: setOnboardingSurveyCompleted
} = useLocalStorage('onboarding-survey-completed', 0)
} = useStorage({ key: 'onboarding-survey-completed', defaultValue: 0 })

const {
value: weeklySurveyLastCompleted,
setValue: setWeeklySurveyLastCompleted
} = useLocalStorage('weekly-survey-last-completed', 0)
} = useStorage({ key: 'weekly-survey-last-completed', defaultValue: 0 })

const {
value: surveyLastDismissed,
setValue: setSurveyLastDismissed
} = useLocalStorage('survey-last-dismissed', 0)
} = useStorage({ key: 'survey-last-dismissed', defaultValue: 0 })

useEffect(() => {
if (!config.onboardingSurveyUrl && !config.weeklySurveyUrl) {
Expand Down Expand Up @@ -333,33 +334,38 @@ export const Header = ({ onMenuClick, isMenuOpen, ...props }: HeaderProps) => {
)}
>
<div className="flex-col-0 lg:pl-0">
<Button
layout="icon"
<IconButton
tooltip={translation('menu')}
color="neutral"
coloringStyle="text"
onClick={onMenuClick}
className="lg:hidden"
>
{isMenuOpen ? <X className="size-6" /> : <MenuIcon className="size-6" />}
</Button>
</IconButton>
</div>
<div className="flex-row-2 justify-end items-center gap-x-2">
<RootLocationSelector className="hidden sm:flex" />
<Tooltip tooltip={translation('feedback')}>
<Button coloringStyle="text" layout="icon" color="neutral" onClick={() => setIsFeedbackOpen(true)}>
<MessageSquare />
</Button>
</Tooltip>
<Tooltip tooltip={translation('settings')}>
<Button coloringStyle="text" layout="icon" color="neutral" onClick={() => router.push('/settings')}>
<SettingsIcon />
</Button>
</Tooltip>
<IconButton
tooltip={translation('feedback')}
coloringStyle="text" color="neutral"
onClick={() => setIsFeedbackOpen(true)}
>
<MessageSquare />
</IconButton>
<IconButton
tooltip={translation('settings')}
coloringStyle="text" color="neutral"
onClick={() => router.push('/settings')}
>
<SettingsIcon />
</IconButton>
<Tooltip tooltip={user?.isOnline ? 'Online' : 'Offline'}>
<Button
onClick={() => setIsUserInfoOpen(!!user?.id)}
coloringStyle="text"
color="neutral"
className="min-w-auto"
>
<span className="hidden sm:inline typography-title-sm">{user?.name}</span>
<AvatarStatusComponent
Expand Down Expand Up @@ -444,15 +450,15 @@ export const Sidebar = ({ isOpen, onClose, ...props }: SidebarProps) => {
<TasksLogo />
<span className="typography-title-md whitespace-nowrap">{'helpwave tasks'}</span>
</Link>
<Button
layout="icon"
<IconButton
tooltip={translation('close')}
color="neutral"
coloringStyle="text"
onClick={onClose}
className="lg:hidden"
>
<X className="size-6" />
</Button>
</IconButton>
</div>
<SidebarLink href="/" onClick={onClose}>
<Grid2X2PlusIcon className="-rotate-90 size-5" />
Expand Down
32 changes: 17 additions & 15 deletions web/components/locations/LocationSelectionDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import {
Checkbox,
Button,
SearchBar,
useLocalStorage
useStorage,
IconButton
} from '@helpwave/hightide'
import { useTasksTranslation } from '@/i18n/useTasksTranslation'
import type { LocationNodeType } from '@/api/gql/generated'
Expand Down Expand Up @@ -148,14 +149,15 @@ const LocationTreeItem = ({
return (
<div className="flex flex-col mb-3">
<Expandable
label={labelContent}
clickOnlyOnHeader={true}
trigger={labelContent}
isExpanded={isExpanded}
onChange={(isOpen) => {
onExpandedChange={(isOpen) => {
onExpandToggle(node.id, isOpen)
}}
className="!shadow-none !bg-transparent !rounded-none w-full"
headerClassName="px-2 hover:bg-surface-hover rounded-lg transition-colors !text-text-primary hover:!text-text-primary flex-row-reverse justify-end cursor-pointer"
triggerProps={{
className: 'px-2 hover:bg-surface-hover rounded-lg transition-colors !text-text-primary hover:!text-text-primary flex-row-reverse justify-end cursor-pointer'
}}
contentExpandedClassName="!max-h-none !h-auto !min-h-0 !overflow-visible !flex !flex-col px-1 data-[expanded]:py-2 border-l-2 border-divider ml-5 pl-2 pr-0 mt-1"
>
<div className="flex flex-col gap-1">
Expand Down Expand Up @@ -194,12 +196,12 @@ export const LocationSelectionDialog = ({
const {
value: storedExpandedIds,
setValue: setStoredExpandedIds
} = useLocalStorage<string[]>(storageKey, [])
} = useStorage<string[]>({ key: storageKey, defaultValue: [] })

const {
value: storedTreeSignature,
setValue: setStoredTreeSignature
} = useLocalStorage<string>(signatureKey, '')
} = useStorage<string>({ key: signatureKey, defaultValue: '' })

const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set(initialSelectedIds))
const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())
Expand Down Expand Up @@ -481,22 +483,22 @@ export const LocationSelectionDialog = ({
</div>

<div className="flex gap-1 border-l border-divider pl-2 ml-1">
<Button layout="icon" size="sm" onClick={handleExpandAll} title={translation('expandAll')}>
<IconButton size="sm" onClick={handleExpandAll} tooltip={translation('expandAll')}>
<ChevronsDown className="size-4" />
</Button>
<Button layout="icon" size="sm" onClick={handleCollapseAll} title={translation('collapseAll')}>
</IconButton>
<IconButton size="sm" onClick={handleCollapseAll} tooltip={translation('collapseAll')}>
<ChevronsUp className="size-4" />
</Button>
</IconButton>
</div>

{multiSelect && useCase !== 'root' && (
<div className="flex gap-1 border-l border-divider pl-2">
<Button layout="icon" size="sm" onClick={handleSelectAll} title={translation('selectAll')}>
<IconButton size="sm" onClick={handleSelectAll} tooltip={translation('selectAll')}>
<CheckSquare className="size-4" />
</Button>
<Button layout="icon" size="sm" onClick={handleDeselectAll} title={translation('deselectAll')}>
</IconButton>
<IconButton size="sm" onClick={handleDeselectAll} tooltip={translation('deselectAll')}>
<Square className="size-4" />
</Button>
</IconButton>
</div>
)}
</div>
Expand Down
53 changes: 25 additions & 28 deletions web/components/patients/PatientDataEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useState, useMemo, useEffect } from 'react'
import type { FormFieldDataHandling } from '@helpwave/hightide'
import { FormProvider, Input, DateTimeInput, Select, SelectOption, Textarea, Checkbox, Button, ConfirmDialog, LoadingContainer, useCreateForm, FormField, Visibility, useFormObserverKey } from '@helpwave/hightide'
import { FormProvider, Input, DateTimeInput, Select, SelectOption, Textarea, Checkbox, Button, ConfirmDialog, LoadingContainer, useCreateForm, FormField, Visibility, useFormObserverKey, IconButton } from '@helpwave/hightide'
import { CenteredLoadingLogo } from '@/components/CenteredLoadingLogo'
import { useTasksTranslation } from '@/i18n/useTasksTranslation'
import type { CreatePatientInput, LocationNodeType, UpdatePatientInput, GetPatientQuery } from '@/api/gql/generated'
Expand Down Expand Up @@ -275,13 +275,13 @@ export const PatientDataEditor = ({
return (
<>
{isRefreshing && (
<div className="flex items-center gap-2 py-2 px-3 rounded-md bg-neutral-100 dark:bg-neutral-800 mb-4">
<div className="flex items-center gap-2 py-2 px-3 rounded-md bg-surface-neutral mb-4">
<LoadingContainer className="size-5 shrink-0" />
<span className="text-sm text-neutral-600 dark:text-neutral-400">{translation('refreshing')}</span>
<span className="text-sm text-on-surface">{translation('refreshing')}</span>
</div>
)}
<FormProvider state={form}>
<form onSubmit={event => {event.preventDefault(); form.submit() }} className="flex-col-4">
<form onSubmit={event => {event.preventDefault(); form.submit() }} className="flex-col-6 pb-16 overflow-y-auto px-2 pt-4">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<FormField<PatientFormValues, 'firstname'>
name="firstname"
Expand Down Expand Up @@ -377,7 +377,9 @@ export const PatientDataEditor = ({
<Checkbox
{...focusableElementProps} {...interactionStates}
value={value === PatientState.Wait}
onValueChange={(value) => onValueChange(value ? PatientState.Wait : PatientState.Admitted)}
onValueChange={(value) => {
onValueChange(value ? PatientState.Wait : PatientState.Admitted)}
}
onEditComplete={(value) => onEditComplete(value ? PatientState.Wait : PatientState.Admitted)}
/>
<span>{translation('waitingForPatient')}</span>
Expand Down Expand Up @@ -446,25 +448,23 @@ export const PatientDataEditor = ({
className="flex-grow cursor-pointer"
onClick={() => setIsClinicDialogOpen(true)}
/>
<Button
<IconButton
onClick={() => setIsClinicDialogOpen(true)}
layout="icon"
title={translation('selectClinic')}
tooltip={translation('selectClinic')}
>
<Building2 className="size-4" />
</Button>
</IconButton>
{value && !isEditMode && (
<Button
<IconButton
onClick={() => {
onValueChange(null)
onEditComplete(null)
}}
layout="icon"
tooltip={translation('clear')}
color="neutral"
title={translation('clear')}
>
<XIcon className="size-5" />
</Button>
</IconButton>
)}
</div>
</div>
Expand All @@ -486,25 +486,23 @@ export const PatientDataEditor = ({
className="flex-grow cursor-pointer"
onClick={() => setIsPositionDialogOpen(true)}
/>
<Button
<IconButton
onClick={() => setIsPositionDialogOpen(true)}
layout="icon"
title={translation('selectPosition')}
tooltip={translation('selectPosition')}
>
<Locate className="size-4" />
</Button>
</IconButton>
{value && (
<Button
<IconButton
onClick={() => {
onValueChange(null)
onEditComplete(null)
}}
layout="icon"
tooltip={translation('clear')}
color="neutral"
title={translation('clear')}
>
<XIcon className="size-5" />
</Button>
</IconButton>
)}
</div>
</div>
Expand All @@ -528,25 +526,24 @@ export const PatientDataEditor = ({
className="flex-grow cursor-pointer"
onClick={() => setIsTeamsDialogOpen(true)}
/>
<Button
<IconButton
onClick={() => setIsTeamsDialogOpen(true)}
layout="icon"
title={translation('selectTeams')}
tooltip={translation('selectTeams')}
>
<Users className="size-4" />
</Button>
</IconButton>
{value && value.length > 0 && (
<Button
<IconButton
onClick={() => {
onValueChange([])
onEditComplete([])
}}
layout="icon"
tooltip={translation('clear')}
color="neutral"
title={translation('clear')}
>
<XIcon className="size-5" />
</Button>
</IconButton>
)}
</div>
</div>
Expand Down
Loading
Loading