2026-08-19 15:05:58 +03:30
|
|
|
'use client';
|
|
|
|
|
|
|
|
|
|
import { Trash2 } from 'lucide-react';
|
|
|
|
|
import { Card } from '@/components/ui/shared/Card';
|
|
|
|
|
import { treatmentTypeBannerStyle } from '@/components/shared/treatmentTypeDisplay';
|
|
|
|
|
import type { TreatmentCatalogEntry } from '@/types/treatment-catalog';
|
|
|
|
|
import type { DayStripItem } from '@/components/treatment/dayStrip';
|
|
|
|
|
|
|
|
|
|
interface DayStripCardProps {
|
|
|
|
|
item: DayStripItem;
|
|
|
|
|
selected: boolean;
|
|
|
|
|
treatmentCatalog: TreatmentCatalogEntry[];
|
|
|
|
|
onSelect: () => void;
|
|
|
|
|
canDelete?: boolean;
|
|
|
|
|
onDelete?: () => void;
|
|
|
|
|
deleteAriaLabel?: string;
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-19 16:07:32 +03:30
|
|
|
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}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-19 15:05:58 +03:30
|
|
|
export function DayStripCard({
|
|
|
|
|
item,
|
|
|
|
|
selected,
|
|
|
|
|
treatmentCatalog,
|
|
|
|
|
onSelect,
|
|
|
|
|
canDelete = false,
|
|
|
|
|
onDelete,
|
|
|
|
|
deleteAriaLabel,
|
|
|
|
|
}: DayStripCardProps) {
|
2026-08-19 16:07:32 +03:30
|
|
|
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>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-19 15:05:58 +03:30
|
|
|
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';
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Card
|
2026-08-19 16:07:32 +03:30
|
|
|
as="button"
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={onSelect}
|
2026-08-19 15:05:58 +03:30
|
|
|
padding="none"
|
|
|
|
|
style={bannerStyle}
|
2026-08-19 16:07:32 +03:30
|
|
|
className={`${shellClass} rounded-[var(--radius-sm)] transition-shadow px-3 py-2 ${selectedClass}`}
|
2026-08-19 15:05:58 +03:30
|
|
|
>
|
2026-08-19 16:07:32 +03:30
|
|
|
<StripCardBody item={item} />
|
2026-08-19 15:05:58 +03:30
|
|
|
</Card>
|
|
|
|
|
);
|
|
|
|
|
}
|