Organize/components/scheduled/scheduled-todo-item.tsx

78 lines
2.6 KiB
TypeScript

"use client";
import { StickyNote } from "lucide-react";
import { cn } from "@/lib/utils";
import { Checkbox } from "@/components/ui/checkbox";
import { MouseFollowTooltip } from "@/components/board/mouse-follow-tooltip";
import type { HoldPhase } from "@/components/hold-on-complete";
import type { ScheduledOccurrenceDTO } from "@/types/scheduled-todo";
/** One occurrence row -- "emphasis" is how loud this date's section reads
* (Overdue/Today get their own text treatment; every other day relies on
* ScheduledPanel fading its whole section via opacity instead). */
export function ScheduledTodoItem({
occurrence,
emphasis = "normal",
holdPhase,
onToggle,
onEdit,
}: {
occurrence: ScheduledOccurrenceDTO;
emphasis?: "overdue" | "today" | "normal";
// Only ever set for Overdue rows -- see ExpandedPanel/useHoldOnComplete.
// A freshly-checked-off one rides this through "visible" -> "fading" ->
// "collapsing" before ExpandedPanel actually drops it from the list.
holdPhase?: HoldPhase;
onToggle: (completed: boolean) => void;
onEdit: () => void;
}) {
const titleButton = (
<button
type="button"
onClick={onEdit}
className={cn(
"min-w-0 flex-1 truncate text-left text-sm hover:underline",
occurrence.completed
? "text-muted-foreground line-through"
: emphasis === "overdue"
? "font-semibold text-destructive"
: emphasis === "today"
? "font-medium text-foreground"
: "text-foreground"
)}
>
{occurrence.title}
</button>
);
return (
<li
className="grid transition-[grid-template-rows] duration-200 ease-in"
style={{ gridTemplateRows: holdPhase === "collapsing" ? "0fr" : "1fr" }}
>
<div className="overflow-hidden">
<div
className="flex items-start gap-2 py-1 transition-opacity duration-1000 ease-in"
style={{ opacity: holdPhase === "fading" || holdPhase === "collapsing" ? 0 : 1 }}
>
<Checkbox
checked={occurrence.completed}
onCheckedChange={(checked) => onToggle(!!checked)}
className="mt-0.5"
aria-label={`Mark "${occurrence.title}" ${occurrence.completed ? "incomplete" : "complete"}`}
/>
{occurrence.details ? (
<MouseFollowTooltip content={occurrence.details}>{titleButton}</MouseFollowTooltip>
) : (
titleButton
)}
{occurrence.details && (
<StickyNote className="mt-0.5 size-3 shrink-0 text-muted-foreground/70" />
)}
</div>
</div>
</li>
);
}