improvement: UI/UX improved for v1 standalone treatments/cases feature.

This commit is contained in:
2026-08-19 16:07:32 +03:30
parent 8bfa8c88fe
commit 96f698be98
24 changed files with 320 additions and 121 deletions

View File

@@ -16,6 +16,25 @@ interface DayStripCardProps {
deleteAriaLabel?: string;
}
function StripCardBody({ item }: { item: DayStripItem }) {
const metaClass = item.kind === 'appointment' ? 'opacity-95' : '';
return (
<>
{item.timeLabel ? (
<p className={`text-[11px] font-medium tabular-nums ${metaClass}`}>{item.timeLabel}</p>
) : (
<p className={`text-[11px] font-medium ${metaClass}`}>{item.subtitle}</p>
)}
<p className="text-sm font-medium leading-tight truncate mt-0.5">
{item.patientFirstName} {item.patientLastName}
</p>
{item.timeLabel ? (
<p className={`text-[11px] mt-0.5 truncate ${metaClass}`}>{item.subtitle}</p>
) : null}
</>
);
}
export function DayStripCard({
item,
selected,
@@ -25,73 +44,70 @@ export function DayStripCard({
onDelete,
deleteAriaLabel,
}: DayStripCardProps) {
const shellClass = `
text-start w-full sm:w-auto sm:min-w-[200px] sm:max-w-[280px] min-h-[52px]
focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/45
`;
if (item.kind === 'unscheduled') {
const selectedClass = selected
? 'border-primary bg-primary-soft'
: 'border-border/70 hover:border-border hover:bg-background-card/50';
const labelClass = selected ? 'font-medium text-text-primary' : 'text-text-secondary';
const trashClass = selected
? 'border-primary/30 text-text-muted hover:bg-red-500/15 hover:text-red-600'
: 'border-border/60 text-text-muted hover:bg-red-500/15 hover:text-red-600';
const showDelete = Boolean(canDelete && onDelete);
return (
<div
className={`inline-flex items-stretch overflow-hidden rounded-[var(--radius-md)] border ${selectedClass} ${shellClass}`}
>
<button
type="button"
onClick={onSelect}
className={`min-w-0 flex-1 text-start px-3 py-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-primary/45 ${labelClass}`}
>
<StripCardBody item={item} />
</button>
{showDelete ? (
<button
type="button"
onClick={(event) => {
event.stopPropagation();
onDelete?.();
}}
aria-label={deleteAriaLabel}
title={deleteAriaLabel}
className={`
shrink-0 inline-flex items-center justify-center border-s px-2 transition-colors
focus:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-red-500/40
${trashClass}
`}
>
<Trash2 className="h-3.5 w-3.5" aria-hidden />
</button>
) : null}
</div>
);
}
const purposeIndex = treatmentCatalog.findIndex((e) => e.code === item.colorCode);
const bannerStyle = treatmentTypeBannerStyle(item.colorCode, purposeIndex < 0 ? 0 : purposeIndex);
const selectedClass = selected
? 'ring-2 ring-primary ring-offset-2 ring-offset-background-secondary shadow-[inset_0_1px_0_rgba(255,255,255,0.06)]'
: 'hover:brightness-110';
const shellClass = `
text-start rounded-[var(--radius-sm)] w-full sm:w-auto sm:min-w-[200px] sm:max-w-[280px] transition-shadow min-h-[52px]
focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/45
${selectedClass}
`;
const body = (
<>
{item.timeLabel ? (
<p className="text-[11px] font-medium tabular-nums opacity-95">{item.timeLabel}</p>
) : (
<p className="text-[11px] font-medium opacity-95">{item.subtitle}</p>
)}
<p className="text-sm font-medium leading-tight truncate mt-0.5">
{item.patientFirstName} {item.patientLastName}
</p>
{item.timeLabel ? (
<p className="text-[11px] opacity-90 mt-0.5 truncate">{item.subtitle}</p>
) : null}
</>
);
if (!canDelete || !onDelete) {
return (
<Card
as="button"
type="button"
onClick={onSelect}
padding="none"
style={bannerStyle}
className={`${shellClass} px-3 py-2`}
>
{body}
</Card>
);
}
return (
<Card
as="button"
type="button"
onClick={onSelect}
padding="none"
style={bannerStyle}
className={`${shellClass} flex items-stretch overflow-hidden`}
className={`${shellClass} rounded-[var(--radius-sm)] transition-shadow px-3 py-2 ${selectedClass}`}
>
<button
type="button"
onClick={onSelect}
className="min-w-0 flex-1 text-start px-3 py-2 focus:outline-none"
>
{body}
</button>
<button
type="button"
onClick={(event) => {
event.stopPropagation();
onDelete();
}}
aria-label={deleteAriaLabel}
title={deleteAriaLabel}
className="shrink-0 self-center pe-2.5 ps-1 opacity-80 hover:opacity-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-primary/45 rounded-[var(--radius-sm)] text-inherit"
>
<Trash2 className="h-4 w-4 text-inherit" aria-hidden />
</button>
<StripCardBody item={item} />
</Card>
);
}