feat: Phase B — interactive dashboard, breadcrumbs, clickable navigation
- Breadcrumb component: reusable nav with items array (label+href)
- DeadlineTrafficLights: buttons → Links to /fristen?status={filter}
- CaseOverviewGrid: static metrics → clickable Links to /cases?status={filter}
- UpcomingTimeline: items → clickable Links to /fristen/{id} or /termine/{id}
with case number links and hover chevron
- QuickActions: swap CalDAV Sync for "Neuer Termin" → /termine/neu,
fix "Frist eintragen" → /fristen/neu
- AISummaryCard: add RefreshCw button with spinning animation
- RecentActivityList: new component showing recent case events
- DeadlineList: accept initialStatus prop, add this_week/ok filters
- fristen/page.tsx: read searchParams.status for initial filter
- Add breadcrumbs to dashboard, fristen, cases, termine pages
- Add RecentActivity type, update DashboardData type
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef } from "react";
|
||||
import Link from "next/link";
|
||||
import { AlertTriangle, Clock, CheckCircle } from "lucide-react";
|
||||
import type { DeadlineSummary } from "@/lib/types";
|
||||
|
||||
@@ -27,10 +28,9 @@ function AnimatedCount({ value }: { value: number }) {
|
||||
|
||||
interface Props {
|
||||
data: DeadlineSummary;
|
||||
onFilter?: (filter: "overdue" | "this_week" | "ok") => void;
|
||||
}
|
||||
|
||||
export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
export function DeadlineTrafficLights({ data }: Props) {
|
||||
const safe = data ?? { overdue_count: 0, due_this_week: 0, due_next_week: 0, ok_count: 0 };
|
||||
const cards = [
|
||||
{
|
||||
@@ -38,6 +38,7 @@ export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
label: "Überfällig",
|
||||
count: safe.overdue_count ?? 0,
|
||||
icon: AlertTriangle,
|
||||
href: "/fristen?status=overdue",
|
||||
bg: "bg-red-50",
|
||||
border: "border-red-200",
|
||||
iconColor: "text-red-500",
|
||||
@@ -51,6 +52,7 @@ export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
label: "Diese Woche",
|
||||
count: safe.due_this_week ?? 0,
|
||||
icon: Clock,
|
||||
href: "/fristen?status=this_week",
|
||||
bg: "bg-amber-50",
|
||||
border: "border-amber-200",
|
||||
iconColor: "text-amber-500",
|
||||
@@ -64,6 +66,7 @@ export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
label: "Im Zeitplan",
|
||||
count: (safe.ok_count ?? 0) + (safe.due_next_week ?? 0),
|
||||
icon: CheckCircle,
|
||||
href: "/fristen?status=ok",
|
||||
bg: "bg-emerald-50",
|
||||
border: "border-emerald-200",
|
||||
iconColor: "text-emerald-500",
|
||||
@@ -77,9 +80,9 @@ export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
{cards.map((card) => (
|
||||
<button
|
||||
<Link
|
||||
key={card.key}
|
||||
onClick={() => onFilter?.(card.key)}
|
||||
href={card.href}
|
||||
className={`group relative overflow-hidden rounded-xl border ${card.border} ${card.bg} ${card.ring} p-6 text-left transition-all hover:shadow-md active:scale-[0.98]`}
|
||||
>
|
||||
{card.pulse && (
|
||||
@@ -99,7 +102,7 @@ export function DeadlineTrafficLights({ data, onFilter }: Props) {
|
||||
<div className={`mt-4 text-4xl font-bold tracking-tight ${card.countColor}`}>
|
||||
<AnimatedCount value={card.count} />
|
||||
</div>
|
||||
</button>
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user