Skip to content

Commit 5ad6131

Browse files
committed
fix property display
1 parent 520d398 commit 5ad6131

4 files changed

Lines changed: 241 additions & 149 deletions

File tree

‎web/components/PropertyList.tsx‎

Lines changed: 146 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { LoadingAndErrorComponent, LoadingAnimation, Menu, MenuItem, ConfirmDialog } from '@helpwave/hightide'
1+
import { LoadingAndErrorComponent, LoadingAnimation, Menu, MenuItem, ConfirmDialog, Button } from '@helpwave/hightide'
22
import { Plus } from 'lucide-react'
3-
import { useMemo, useState, useEffect } from 'react'
3+
import React, { useMemo, useState, useEffect } from 'react'
44
import { useTasksTranslation } from '@/i18n/useTasksTranslation'
55
import { PropertyEntry } from '@/components/PropertyEntry'
66
import { useGetPropertyDefinitionsQuery, FieldType, PropertyEntity } from '@/api/gql/generated'
@@ -218,6 +218,7 @@ export type PropertyListProps = {
218218
multiSelectValues?: string[] | null,
219219
}>,
220220
onPropertyValueChange?: (definitionId: string, value: PropertyValue) => void,
221+
fullWidthAddButton?: boolean,
221222
}
222223

223224
const mapFieldTypeFromBackend = (fieldType: FieldType): PropertyFieldType => {
@@ -242,7 +243,8 @@ export const PropertyList = ({
242243
subjectId,
243244
subjectType,
244245
propertyValues = [],
245-
onPropertyValueChange
246+
onPropertyValueChange,
247+
fullWidthAddButton = false,
246248
}: PropertyListProps) => {
247249
const translation = useTasksTranslation()
248250

@@ -397,71 +399,151 @@ export const PropertyList = ({
397399
/>
398400
)
399401
})}
400-
{availableProperties.length > 0 && (
401-
<Menu<HTMLDivElement>
402-
trigger={({ toggleOpen }, ref) => (
403-
<div
404-
ref={ref}
405-
className="flex-row-4 px-4 py-2 items-center border-2 border-dashed bg-property-title-background text-property-title-text hover:border-primary rounded-xl cursor-pointer"
406-
onClick={toggleOpen}
402+
{fullWidthAddButton && (
403+
<div className="w-full">
404+
{availableProperties.length > 0 ? (
405+
<Menu<HTMLButtonElement>
406+
trigger={({ toggleOpen }, ref) => (
407+
<Button
408+
ref={ref}
409+
startIcon={<Plus size={20} />}
410+
onClick={toggleOpen}
411+
className="w-full"
412+
>
413+
{translation('addProperty')}
414+
</Button>
415+
)}
416+
menuClassName="min-w-[200px] p-2 "
417+
alignmentVertical="topOutside"
407418
>
408-
<Plus size={20} />
409-
<span>{translation('addProperty')}</span>
410-
</div>
411-
)}
412-
menuClassName="min-w-[200px] p-2 "
413-
alignmentVertical="topOutside"
414-
>
415-
{({ close }) => (
416-
<LoadingAndErrorComponent
417-
isLoading={isLoading}
418-
hasError={isError}
419-
loadingComponent={<LoadingAnimation classname="min-h-20" />}
420-
>
421-
{availableProperties
422-
.filter(prop => !attachedProperties.some(attached => attached.property.id === prop.id))
423-
.map(property => {
424-
const getDefaultValue = (): PropertyValue => {
425-
switch (property.fieldType) {
426-
case 'text':
427-
return { textValue: '' }
428-
case 'number':
429-
return { numberValue: undefined }
430-
case 'checkbox':
431-
return { boolValue: false }
432-
case 'date':
433-
case 'dateTime':
434-
return {}
435-
case 'singleSelect':
436-
return property.selectData?.options && property.selectData.options.length > 0
437-
? { singleSelectValue: property.selectData.options[0]?.id || undefined }
438-
: {}
439-
case 'multiSelect':
440-
return { multiSelectValue: [] }
441-
default:
442-
return {}
419+
{({ close }) => (
420+
<LoadingAndErrorComponent
421+
isLoading={isLoading}
422+
hasError={isError}
423+
loadingComponent={<LoadingAnimation classname="min-h-20" />}
424+
>
425+
{availableProperties
426+
.filter(prop => !attachedProperties.some(attached => attached.property.id === prop.id))
427+
.map(property => {
428+
const getDefaultValue = (): PropertyValue => {
429+
switch (property.fieldType) {
430+
case 'text':
431+
return { textValue: '' }
432+
case 'number':
433+
return { numberValue: undefined }
434+
case 'checkbox':
435+
return { boolValue: false }
436+
case 'date':
437+
case 'dateTime':
438+
return {}
439+
case 'singleSelect':
440+
return property.selectData?.options && property.selectData.options.length > 0
441+
? { singleSelectValue: property.selectData.options[0]?.id || undefined }
442+
: {}
443+
case 'multiSelect':
444+
return { multiSelectValue: [] }
445+
default:
446+
return {}
447+
}
443448
}
444-
}
445449

446-
return (
447-
<MenuItem
448-
key={property.id}
449-
onClick={() => {
450-
if (onPropertyValueChange) {
451-
const defaultValue = getDefaultValue()
452-
onPropertyValueChange(property.id, defaultValue)
453-
}
454-
close()
455-
}}
456-
className="rounded-md cursor-pointer"
457-
>
458-
{property.name}
459-
</MenuItem>
460-
)
461-
})}
462-
</LoadingAndErrorComponent>
450+
return (
451+
<MenuItem
452+
key={property.id}
453+
onClick={() => {
454+
if (onPropertyValueChange) {
455+
const defaultValue = getDefaultValue()
456+
onPropertyValueChange(property.id, defaultValue)
457+
}
458+
close()
459+
}}
460+
className="rounded-md cursor-pointer"
461+
>
462+
{property.name}
463+
</MenuItem>
464+
)
465+
})}
466+
</LoadingAndErrorComponent>
467+
)}
468+
</Menu>
469+
) : (
470+
<Button
471+
startIcon={<Plus size={20} />}
472+
disabled={true}
473+
className="w-full"
474+
>
475+
{translation('addProperty')}
476+
</Button>
463477
)}
464-
</Menu>
478+
</div>
479+
)}
480+
{!fullWidthAddButton && (
481+
availableProperties.length > 0 && (
482+
<Menu<HTMLDivElement>
483+
trigger={({ toggleOpen }, ref) => (
484+
<div
485+
ref={ref as React.RefObject<HTMLDivElement>}
486+
className="flex-row-4 px-4 py-2 items-center border-2 border-dashed bg-property-title-background text-property-title-text hover:border-primary rounded-xl cursor-pointer"
487+
onClick={toggleOpen}
488+
>
489+
<Plus size={20} />
490+
<span>{translation('addProperty')}</span>
491+
</div>
492+
)}
493+
menuClassName="min-w-[200px] p-2 "
494+
alignmentVertical="topOutside"
495+
>
496+
{({ close }) => (
497+
<LoadingAndErrorComponent
498+
isLoading={isLoading}
499+
hasError={isError}
500+
loadingComponent={<LoadingAnimation classname="min-h-20" />}
501+
>
502+
{availableProperties
503+
.filter(prop => !attachedProperties.some(attached => attached.property.id === prop.id))
504+
.map(property => {
505+
const getDefaultValue = (): PropertyValue => {
506+
switch (property.fieldType) {
507+
case 'text':
508+
return { textValue: '' }
509+
case 'number':
510+
return { numberValue: undefined }
511+
case 'checkbox':
512+
return { boolValue: false }
513+
case 'date':
514+
case 'dateTime':
515+
return {}
516+
case 'singleSelect':
517+
return property.selectData?.options && property.selectData.options.length > 0
518+
? { singleSelectValue: property.selectData.options[0]?.id || undefined }
519+
: {}
520+
case 'multiSelect':
521+
return { multiSelectValue: [] }
522+
default:
523+
return {}
524+
}
525+
}
526+
527+
return (
528+
<MenuItem
529+
key={property.id}
530+
onClick={() => {
531+
if (onPropertyValueChange) {
532+
const defaultValue = getDefaultValue()
533+
onPropertyValueChange(property.id, defaultValue)
534+
}
535+
close()
536+
}}
537+
className="rounded-md cursor-pointer"
538+
>
539+
{property.name}
540+
</MenuItem>
541+
)
542+
})}
543+
</LoadingAndErrorComponent>
544+
)}
545+
</Menu>
546+
)
465547
)}
466548
</div>
467549
<ConfirmDialog

‎web/components/layout/Page.tsx‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,10 +249,18 @@ const RootLocationSelector = ({ className, onSelect }: RootLocationSelectorProps
249249
}
250250
}, [rootLocations, selectedRootLocationIds, locationsData])
251251

252+
// Auto-open dialog if no location is selected
253+
useEffect(() => {
254+
if (rootLocations && rootLocations.length > 0 && (!selectedRootLocationIds || selectedRootLocationIds.length === 0)) {
255+
setIsLocationPickerOpen(true)
256+
}
257+
}, [rootLocations, selectedRootLocationIds])
258+
252259
const selectedRootLocations = selectedLocationsCache.length > 0
253260
? selectedLocationsCache
254261
: (rootLocations?.filter(loc => selectedRootLocationIds?.includes(loc.id)) || [])
255262
const firstSelectedRootLocation = selectedRootLocations[0]
263+
const hasNoLocationSelected = !selectedRootLocationIds || selectedRootLocationIds.length === 0
256264

257265
const handleRootLocationSelect = (locations: Array<{ id: string, title: string, kind?: string }>) => {
258266
if (locations.length === 0) return
@@ -276,7 +284,7 @@ const RootLocationSelector = ({ className, onSelect }: RootLocationSelectorProps
276284
<div className={clsx('flex-row-1 items-center gap-x-1', className)}>
277285
<Button
278286
onClick={() => setIsLocationPickerOpen(true)}
279-
color="neutral"
287+
color={hasNoLocationSelected ? 'negative' : 'neutral'}
280288
coloringStyle="outline"
281289
className="min-w-40 w-full"
282290
>

‎web/components/patients/PatientDetailView.tsx‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,7 @@ export const PatientDetailView = ({
708708
<PropertyList
709709
subjectId={patientId!}
710710
subjectType="patient"
711+
fullWidthAddButton={true}
711712
propertyValues={patientData?.patient?.properties?.map(p => ({
712713
definition: {
713714
id: p.definition.id,

0 commit comments

Comments
 (0)