- Responsive sidebar: collapses on mobile with hamburger menu, slide-in animation - Skeleton loaders: dashboard cards, case table, case detail page - Empty states: friendly messages with icons for cases, deadlines, parties, documents - Error states: retry button on dashboard, proper error message on case not found - Form validation: inline error messages on case creation form - German language: fix all missing umlauts (Zurück, wählen, Anhängig, Verfügung, etc.) - Status labels: display German translations instead of raw status values - Transitions: fade-in animations on page load, hover/transition-colors on all interactive elements - Focus states: focus-visible ring for keyboard accessibility - Mobile layout: stacking for filters, forms, tabs; horizontal scroll for tables - Extraction results: card layout on mobile, table on desktop - Missing types: add DashboardData, DeadlineSummary, CaseSummary, ExtractedDeadline etc. - Fix QuickActions links to use correct routes (/cases/new, /ai/extract) - Consistent input focus styles across all forms
74 lines
2.6 KiB
TypeScript
74 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { DeadlineList } from "@/components/deadlines/DeadlineList";
|
|
import { DeadlineCalendarView } from "@/components/deadlines/DeadlineCalendarView";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { api } from "@/lib/api";
|
|
import type { Deadline } from "@/lib/types";
|
|
import { Calendar, List, Calculator } from "lucide-react";
|
|
import Link from "next/link";
|
|
import { useState } from "react";
|
|
|
|
type ViewMode = "list" | "calendar";
|
|
|
|
export default function FristenPage() {
|
|
const [view, setView] = useState<ViewMode>("list");
|
|
|
|
const { data: deadlines } = useQuery({
|
|
queryKey: ["deadlines"],
|
|
queryFn: () => api.get<Deadline[]>("/api/deadlines"),
|
|
});
|
|
|
|
return (
|
|
<div className="animate-fade-in space-y-4">
|
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>
|
|
<h1 className="text-lg font-semibold text-neutral-900">Fristen</h1>
|
|
<p className="mt-0.5 text-sm text-neutral-500">
|
|
Alle Fristen im Überblick
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<Link
|
|
href="/fristen/rechner"
|
|
className="flex items-center gap-1.5 rounded-md border border-neutral-200 bg-white px-3 py-1.5 text-sm text-neutral-700 transition-colors hover:bg-neutral-50"
|
|
>
|
|
<Calculator className="h-3.5 w-3.5" />
|
|
Fristenrechner
|
|
</Link>
|
|
<div className="flex rounded-md border border-neutral-200 bg-white">
|
|
<button
|
|
onClick={() => setView("list")}
|
|
className={`flex items-center gap-1 rounded-l-md px-2.5 py-1.5 text-sm transition-colors ${
|
|
view === "list"
|
|
? "bg-neutral-100 font-medium text-neutral-900"
|
|
: "text-neutral-500 hover:text-neutral-700"
|
|
}`}
|
|
>
|
|
<List className="h-3.5 w-3.5" />
|
|
Liste
|
|
</button>
|
|
<button
|
|
onClick={() => setView("calendar")}
|
|
className={`flex items-center gap-1 rounded-r-md px-2.5 py-1.5 text-sm transition-colors ${
|
|
view === "calendar"
|
|
? "bg-neutral-100 font-medium text-neutral-900"
|
|
: "text-neutral-500 hover:text-neutral-700"
|
|
}`}
|
|
>
|
|
<Calendar className="h-3.5 w-3.5" />
|
|
Kalender
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{view === "list" ? (
|
|
<DeadlineList />
|
|
) : (
|
|
<DeadlineCalendarView deadlines={deadlines || []} />
|
|
)}
|
|
</div>
|
|
);
|
|
}
|