- 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
107 lines
3.4 KiB
TypeScript
107 lines
3.4 KiB
TypeScript
"use client";
|
|
|
|
import { AppointmentList } from "@/components/appointments/AppointmentList";
|
|
import { AppointmentCalendar } from "@/components/appointments/AppointmentCalendar";
|
|
import { AppointmentModal } from "@/components/appointments/AppointmentModal";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { api } from "@/lib/api";
|
|
import type { Appointment } from "@/lib/types";
|
|
import { Breadcrumb } from "@/components/layout/Breadcrumb";
|
|
import { Calendar, List, Plus } from "lucide-react";
|
|
import { useState } from "react";
|
|
|
|
type ViewMode = "list" | "calendar";
|
|
|
|
export default function TerminePage() {
|
|
const [view, setView] = useState<ViewMode>("list");
|
|
const [modalOpen, setModalOpen] = useState(false);
|
|
const [editingAppointment, setEditingAppointment] = useState<Appointment | null>(null);
|
|
|
|
const { data: appointments } = useQuery({
|
|
queryKey: ["appointments"],
|
|
queryFn: () => api.get<Appointment[]>("/appointments"),
|
|
});
|
|
|
|
function handleEdit(appointment: Appointment) {
|
|
setEditingAppointment(appointment);
|
|
setModalOpen(true);
|
|
}
|
|
|
|
function handleCreate() {
|
|
setEditingAppointment(null);
|
|
setModalOpen(true);
|
|
}
|
|
|
|
function handleClose() {
|
|
setModalOpen(false);
|
|
setEditingAppointment(null);
|
|
}
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<Breadcrumb
|
|
items={[
|
|
{ label: "Dashboard", href: "/dashboard" },
|
|
{ label: "Termine" },
|
|
]}
|
|
/>
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h1 className="text-lg font-semibold text-neutral-900">Termine</h1>
|
|
<p className="mt-0.5 text-sm text-neutral-500">
|
|
Alle Termine im Uberblick
|
|
</p>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={handleCreate}
|
|
className="flex items-center gap-1.5 rounded-md bg-neutral-900 px-3 py-1.5 text-sm font-medium text-white hover:bg-neutral-800"
|
|
>
|
|
<Plus className="h-3.5 w-3.5" />
|
|
Neuer Termin
|
|
</button>
|
|
<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" ? (
|
|
<AppointmentList onEdit={handleEdit} />
|
|
) : (
|
|
<AppointmentCalendar
|
|
appointments={Array.isArray(appointments) ? appointments : []}
|
|
onAppointmentClick={handleEdit}
|
|
/>
|
|
)}
|
|
|
|
<AppointmentModal
|
|
open={modalOpen}
|
|
onClose={handleClose}
|
|
appointment={editingAppointment}
|
|
/>
|
|
</div>
|
|
);
|
|
}
|