diff --git a/components/deadlines/DeadlineCard.tsx b/components/deadlines/DeadlineCard.tsx
index 18bea351..844f264e 100644
--- a/components/deadlines/DeadlineCard.tsx
+++ b/components/deadlines/DeadlineCard.tsx
@@ -8,9 +8,10 @@ import {
isDeadlineOverdue,
DEADLINE_TYPE_LABELS,
PRIORITY_LABELS,
- PRIORITY_COLORS,
+ parseDate,
+ startOfDay,
} from '@/lib/calendar/utils'
-import { CheckCircle, Circle, Clock, AlertTriangle, Trash2, Edit2 } from 'lucide-react'
+import { Check, Circle, Trash2, Pencil } from 'lucide-react'
interface DeadlineCardProps {
deadline: Deadline
@@ -20,6 +21,25 @@ interface DeadlineCardProps {
compact?: boolean
}
+function getRelativeDate(dateStr: string): string {
+ const today = startOfDay(new Date())
+ const target = parseDate(dateStr)
+ const diffMs = target.getTime() - today.getTime()
+ const diffDays = Math.round(diffMs / (1000 * 60 * 60 * 24))
+
+ if (diffDays === 0) return 'Idag'
+ if (diffDays === 1) return 'Imorgon'
+ if (diffDays === -1) return 'Igår'
+ if (diffDays < -1) return `${Math.abs(diffDays)}d sedan`
+ if (diffDays <= 14) return `Om ${diffDays}d`
+ return ''
+}
+
+const SWEDISH_MONTHS_SHORT = [
+ 'jan', 'feb', 'mar', 'apr', 'maj', 'jun',
+ 'jul', 'aug', 'sep', 'okt', 'nov', 'dec',
+]
+
export function DeadlineCard({
deadline,
onToggle,
@@ -29,56 +49,48 @@ export function DeadlineCard({
}: DeadlineCardProps) {
const overdue = isDeadlineOverdue(deadline)
const completed = deadline.is_completed
- const priorityStyle = PRIORITY_COLORS[deadline.priority]
-
- const formatDueDate = () => {
- const date = new Date(deadline.due_date)
- const formatted = date.toLocaleDateString('sv-SE', {
- day: 'numeric',
- month: 'short',
- })
- if (deadline.due_time) {
- return `${formatted} kl. ${deadline.due_time.slice(0, 5)}`
- }
- return formatted
- }
+ const relativeDate = getRelativeDate(deadline.due_date)
+ const dueDate = parseDate(deadline.due_date)
+ const dayNum = dueDate.getDate()
+ const monthStr = SWEDISH_MONTHS_SHORT[dueDate.getMonth()]
if (compact) {
return (
-
-
- {deadline.priority !== 'normal' && !completed && (
-
+
)
@@ -87,89 +99,151 @@ export function DeadlineCard({
return (
-
-
+
+ {/* Date block — calendar page motif */}
+
+
+ {dayNum}
+
+
+ {monthStr}
+
+
-
-
-
-
+ {/* Top: title + hover actions */}
+
+
+ {/* Toggle */}
+
+
+
+
+ {deadline.title}
+
+
+ {/* Meta line */}
+
+ {deadline.due_time && (
+
+ kl. {deadline.due_time.slice(0, 5)}
+
+ )}
+ {deadline.due_time && (deadline.customer || (!completed && relativeDate)) && (
+ ·
+ )}
+ {!completed && relativeDate && (
+
+ {relativeDate}
+
+ )}
+ {relativeDate && deadline.customer && !completed && (
+ ·
+ )}
+ {deadline.customer && (
+
+ {deadline.customer.name}
+
+ )}
+
+
-
-
- {DEADLINE_TYPE_LABELS[deadline.deadline_type]}
-
- {!completed && deadline.priority !== 'normal' && (
+ {/* Right column: badges + actions */}
+
+ {/* Badges */}
+
- {PRIORITY_LABELS[deadline.priority]}
-
- )}
- {overdue && !completed && (
-
- Förfallen
+ {DEADLINE_TYPE_LABELS[deadline.deadline_type]}
+ {!completed && deadline.priority !== 'normal' && (
+
+ {PRIORITY_LABELS[deadline.priority]}
+
+ )}
+ {overdue && !completed && (
+
+ Förfallen
+
+ )}
+
+
+ {/* Actions */}
+ {(onEdit || onDelete) && !completed && (
+
+
+ {onEdit && (
+
+ )}
+ {onDelete && (
+
+ )}
+
)}
- {deadline.notes && (
-
+ {/* Notes */}
+ {deadline.notes && !completed && (
+
{deadline.notes}
)}
-
- {(onEdit || onDelete) && (
-
- {onEdit && (
-
- )}
- {onDelete && (
-
- )}
-
- )}
)
}
diff --git a/components/deadlines/DeadlineList.tsx b/components/deadlines/DeadlineList.tsx
index 9e9d5180..3a6fb95b 100644
--- a/components/deadlines/DeadlineList.tsx
+++ b/components/deadlines/DeadlineList.tsx
@@ -111,23 +111,29 @@ export function DeadlineList({
{/* Deadline groups */}
{filteredDeadlines.length === 0 ? (
-
-
-
Inga deadlines
-
+
+
+
Inga deadlines
+
{statusFilter !== 'all' || typeFilter !== 'all'
? 'Inga deadlines matchar dina filter'
: 'Skapa din första deadline för att komma igång'}
) : (
-
+
{/* Overdue */}
{groupedDeadlines.overdue.length > 0 && (
-
-
- Förfallna ({groupedDeadlines.overdue.length})
-
+
+
+
+ Förfallna
+
+
+ {groupedDeadlines.overdue.length}
+
+
+
{groupedDeadlines.overdue.map((deadline) => (
))}
-
+
)}
{/* Today */}
{groupedDeadlines.today.length > 0 && (
-
-
- Idag ({groupedDeadlines.today.length})
-
+
+
+
+ Idag
+
+
+ {groupedDeadlines.today.length}
+
+
+
{groupedDeadlines.today.map((deadline) => (
))}
-
+
)}
{/* Upcoming */}
{groupedDeadlines.upcoming.length > 0 && (
-
-
- Kommande ({groupedDeadlines.upcoming.length})
-
+
+
+
+ Kommande
+
+
+ {groupedDeadlines.upcoming.length}
+
+
+
{groupedDeadlines.upcoming.map((deadline) => (
))}
-
+
)}
{/* Completed */}
{groupedDeadlines.completed.length > 0 && (
-
-
- Klara ({groupedDeadlines.completed.length})
-
+
+
+
+ Klara
+
+
+ {groupedDeadlines.completed.length}
+
+
+
{groupedDeadlines.completed.map((deadline) => (
))}
-
+
)}
)}
diff --git a/lib/api/schemas.ts b/lib/api/schemas.ts
index 8644e682..7fb62a09 100644
--- a/lib/api/schemas.ts
+++ b/lib/api/schemas.ts
@@ -450,16 +450,16 @@ export const EvaluateMappingRulesSchema = z.union([
export const CreateDeadlineSchema = z.object({
title: z.string().min(1, 'Title is required'),
due_date: isoDate,
- due_time: timeString.optional(),
+ due_time: timeString.nullish(),
deadline_type: DeadlineTypeSchema,
- priority: DeadlinePrioritySchema.optional(),
- customer_id: uuid.optional(),
- notes: z.string().optional(),
- tax_deadline_type: TaxDeadlineTypeSchema.optional(),
- tax_period: z.string().optional(),
+ priority: DeadlinePrioritySchema.nullish(),
+ customer_id: uuid.nullish(),
+ notes: z.string().nullish(),
+ tax_deadline_type: TaxDeadlineTypeSchema.nullish(),
+ tax_period: z.string().nullish(),
source: DeadlineSourceSchema.optional(),
- linked_report_type: z.string().optional(),
- linked_report_period: z.record(z.string(), z.unknown()).optional(),
+ linked_report_type: z.string().nullish(),
+ linked_report_period: z.record(z.string(), z.unknown()).nullish(),
})
// ============================================================
diff --git a/lib/calendar/utils.ts b/lib/calendar/utils.ts
index a0eb93be..8ca9d1d4 100644
--- a/lib/calendar/utils.ts
+++ b/lib/calendar/utils.ts
@@ -242,9 +242,9 @@ export const PRIORITY_LABELS: Record
= {
// Priority colors for styling
export const PRIORITY_COLORS: Record = {
- critical: { bg: 'bg-red-50', text: 'text-red-700', border: 'border-red-200' },
- important: { bg: 'bg-orange-50', text: 'text-orange-700', border: 'border-orange-200' },
- normal: { bg: 'bg-gray-50', text: 'text-gray-700', border: 'border-gray-200' }
+ critical: { bg: 'bg-red-50 dark:bg-red-950/40', text: 'text-red-700 dark:text-red-400', border: 'border-red-200 dark:border-red-800/50' },
+ important: { bg: 'bg-orange-50 dark:bg-orange-950/40', text: 'text-orange-700 dark:text-orange-400', border: 'border-orange-200 dark:border-orange-800/50' },
+ normal: { bg: 'bg-gray-50 dark:bg-gray-800/40', text: 'text-gray-700 dark:text-gray-300', border: 'border-gray-200 dark:border-gray-700/50' }
}
// ============================================================