"use client"; import { useQuery } from "@tanstack/react-query"; import { api } from "@/lib/api"; import type { TimeEntry } from "@/lib/types"; import { format } from "date-fns"; import { de } from "date-fns/locale"; import { Timer, Loader2 } from "lucide-react"; import { useState } from "react"; import Link from "next/link"; import { Breadcrumb } from "@/components/layout/Breadcrumb"; function formatDuration(minutes: number): string { const h = Math.floor(minutes / 60); const m = minutes % 60; if (h === 0) return `${m}min`; if (m === 0) return `${h}h`; return `${h}h ${m}min`; } export default function AbrechnungPage() { const [from, setFrom] = useState(() => { const d = new Date(); d.setDate(1); return format(d, "yyyy-MM-dd"); }); const [to, setTo] = useState(() => format(new Date(), "yyyy-MM-dd")); const { data, isLoading } = useQuery({ queryKey: ["time-entries", from, to], queryFn: () => api.get<{ time_entries: TimeEntry[]; total: number }>( `/time-entries?from=${from}&to=${to}&limit=100`, ), }); const entries = data?.time_entries ?? []; const totalMinutes = entries.reduce((s, e) => s + e.duration_minutes, 0); const billableMinutes = entries .filter((e) => e.billable) .reduce((s, e) => s + e.duration_minutes, 0); const totalAmount = entries .filter((e) => e.billable && e.hourly_rate) .reduce((s, e) => s + (e.duration_minutes / 60) * (e.hourly_rate ?? 0), 0); return (

Zeiterfassung

Rechnungen ansehen →
{/* Filters */}
setFrom(e.target.value)} className="rounded-md border border-neutral-300 px-2 py-1 text-sm focus:border-neutral-500 focus:outline-none" />
setTo(e.target.value)} className="rounded-md border border-neutral-300 px-2 py-1 text-sm focus:border-neutral-500 focus:outline-none" />
{/* Summary cards */}

Gesamt

{formatDuration(totalMinutes)}

Abrechenbar

{formatDuration(billableMinutes)}

Betrag

{totalAmount.toFixed(2)} EUR

{/* Entries */} {isLoading ? (
) : entries.length === 0 ? (

Keine Zeiteintraege im gewaehlten Zeitraum.

) : (
{entries.map((entry) => (

{entry.description}

{format(new Date(entry.date), "d. MMM yyyy", { locale: de })} Akte ansehen
{entry.billable ? ( abrechenbar ) : ( intern )} {formatDuration(entry.duration_minutes)}
))}
)}
); }