import { type Component, createMemo, For, Show } from "solid-js"; import { type Task, calculateUrgencyFromDate, setActiveTaskId, store, copyTask, updateTask, currentTaskContext, now, getFavoriteTag, isCurrentUserContextTag, dismissTaskUpdateIndicator, isTaskUpdatedByAnotherUser, collapseTaskUntilUpdated, expandCollapsedTask, isTaskCollapsedUntilUpdated, isTaskCollaborativelyShared } from "@/store"; import { cn } from "@/lib/utils"; import { Clock, ArrowUpCircle, Copy, Users2, Star, ChevronRight } from "lucide-solid"; import { Badge } from "@/components/ui/badge"; import { useTheme } from "./ThemeProvider"; import { getThemeAdjustedColor } from "@/lib/colors"; import { Select, SelectContent, SelectItem, SelectTrigger } from "@/components/ui/select"; import { getStatusOptionsForTask } from "@/lib/constants"; import { getRecurrenceProgress } from "@/lib/recurrence"; import { buildShareTag } from "@/lib/tags"; import { StatusCircle } from "./StatusCircle"; export const TaskCard: Component<{ task: Task, isShaking?: boolean }> = (props) => { const { resolvedTheme } = useTheme(); const urgencyLevel = createMemo(() => calculateUrgencyFromDate(props.task.dueDate)); const urgencyColor = () => { const u = urgencyLevel(); if (u >= 8) return "text-red-500"; if (u >= 6) return "text-orange-500"; if (u >= 4) return "text-blue-500"; return "text-muted-foreground"; }; const formattedDate = () => { const date = new Date(props.task.dueDate); return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit' }); }; // Filter out bucket tags if we are currently INSIDE that bucket view const visibleTags = createMemo(() => { const tags = props.task.tags || []; const ctx = currentTaskContext(); if (typeof ctx === 'object' && 'bucketId' in ctx) { const bucketContext = store.contexts.find(context => context.id === ctx.bucketId); const bucketTagName = buildShareTag(bucketContext?.displayName || ctx.name).toLowerCase(); return tags.filter(t => t.toLowerCase() !== bucketTagName && !t.endsWith("_favorite__") && !isCurrentUserContextTag(t)); } return tags.filter(t => !t.endsWith("_favorite__") && !isCurrentUserContextTag(t)); }); const isDueWithin12Hours = createMemo(() => { if (!props.task.dueDate) return false; try { const dueMs = new Date(props.task.dueDate).getTime(); const diffMs = dueMs - now(); const twelveHoursMs = 12 * 60 * 60 * 1000; return Math.abs(diffMs) <= twelveHoursMs; } catch { return false; } }); const canCollapseUntilUpdated = createMemo(() => isTaskCollaborativelyShared(props.task)); const statusOptions = createMemo(() => { const baseOptions = getStatusOptionsForTask(props.task.recurrence); if (!canCollapseUntilUpdated()) return baseOptions; return [ ...baseOptions, { value: "__collapse_until_updated__", label: "Collapse until updated" } ]; }); const recurrenceProgress = createMemo(() => { if (props.task.status !== 10) return null; return getRecurrenceProgress(props.task.recurrence, props.task.updated, now()); }); const shouldQuickloadFade = createMemo(() => store.quickloadFadeTaskIds.includes(props.task.id)); const showUpdateIndicator = createMemo(() => isTaskUpdatedByAnotherUser(props.task)); const isCollapsed = createMemo(() => isTaskCollapsedUntilUpdated(props.task)); return (