"use client"; import { use, useState } from "react"; import Link from "next/link"; import { BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, Cell, } from "recharts"; import { useTripAnalytics, useTrip, useTransactions } from "@/lib/hooks"; import { CreateTripModal } from "@/components/create-trip-modal"; import { formatCategory } from "@/lib/categories"; import { CATEGORY_COLORS, TOOLTIP_STYLE } from "@/lib/category-colors"; function fmtDate(d: string | null) { if (!d) return null; return new Date(d).toLocaleDateString("en-AU", { day: "2-digit", month: "short", year: "numeric" }); } function StatCard({ label, value, sub, color, }: { label: string; value: string; sub?: string; color: string; }) { return (

{label}

{value}

{sub &&

{sub}

}
); } function DailyTooltip({ active, payload, label }: { active?: boolean; payload?: { value: number }[]; label?: string }) { if (!active || !payload?.length) return null; return (

{label ? new Date(label).toLocaleDateString("en-AU", { day: "2-digit", month: "short", year: "numeric" }) : ""}

${Number(payload[0].value).toFixed(2)}

); } function CategoryTooltip({ active, payload }: { active?: boolean; payload?: { payload: { category: string }; value: number }[] }) { if (!active || !payload?.length) return null; return (

{formatCategory(payload[0].payload.category)}

${Number(payload[0].value).toFixed(2)}

); } export default function TripDetailPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const tripId = Number(id); const { data: analytics, isLoading } = useTripAnalytics(tripId); const { data: trip } = useTrip(tripId); const [tab, setTab] = useState<"overview" | "transactions">("overview"); const [editModal, setEditModal] = useState(false); const { data: txData } = useTransactions({ trip_id: id, limit: 500 }); if (isLoading || !analytics) { return (
{[...Array(4)].map((_, i) =>
)}
); } const { total_spend, transaction_count, num_days, daily_average, category_breakdown, daily_spend, top_merchants, tag_breakdown, participant_splits } = analytics; const t = analytics.trip; const maxMerchant = top_merchants[0]?.amount ?? 1; const dateRange = t.start_date && t.end_date ? `${fmtDate(t.start_date)} – ${fmtDate(t.end_date)}` : t.start_date ? `From ${fmtDate(t.start_date)}` : null; return (
{/* Hero */}
← Trips

{t.name}

{dateRange &&

{dateRange}

} {t.description &&

{t.description}

}
{/* Stat cards */}
{/* Tab bar */}
{(["overview", "transactions"] as const).map((tabName) => ( ))}
{tab === "overview" && (
{/* Daily spend */} {daily_spend.length > 0 && (

Daily Spend

new Date(v).toLocaleDateString("en-AU", { day: "2-digit", month: "short" })} interval="preserveStartEnd" /> `$${v}`} width={52} /> } cursor={{ fill: "#27272a" }} />
)}
{/* Category breakdown */} {category_breakdown.length > 0 && (

By Category

`$${v}`} /> } cursor={{ fill: "#27272a" }} /> {category_breakdown.map((entry) => ( ))}
)} {/* Top merchants */} {top_merchants.length > 0 && (

Top Merchants

{top_merchants.map((m, i) => (
{i + 1}
{m.merchant || "Unknown"} ${Number(m.amount).toFixed(2)}
))}
)}
{/* Tag breakdown */} {tag_breakdown.length > 0 && (

By Tag

{tag_breakdown.map((tag) => (
{tag.name} {tag.count} txns ${Number(tag.amount).toFixed(2)}
))}
)} {/* Participant splits */} {participant_splits.length > 0 && (

Participant Splits

View in Shared →
{["Person", "Share of this trip"].map((h) => ( ))} {participant_splits.map((p) => ( ))}
{h}
{p.name} ${Number(p.owed).toFixed(2)}
{/* Settled/unsettled was reported from transaction_splits.settled, which nothing sets — so every trip showed 100% unsettled forever, including ones already paid in full. Settlement is tracked across the whole relationship, not per trip: payments carry no trip attribution, so a per-trip figure cannot be computed. */}

Settlement is tracked across all shared expenses, not per trip — see Shared for what is actually owed.

)} {category_breakdown.length === 0 && daily_spend.length === 0 && (

No transactions assigned to this trip yet.

Go to Transactions to assign some →
)}
)} {tab === "transactions" && (
{!txData?.data.length ? (

No transactions assigned to this trip yet.

Go to Transactions to assign some →
) : (
{["Date", "Description", "Merchant", "Category", "Amount"].map((h) => ( ))} {txData.data.map((tx) => ( ))}
{h}
{new Date(tx.transaction_date).toLocaleDateString("en-AU", { day: "2-digit", month: "short" })} {tx.description} {tx.effective_merchant || "—"} {formatCategory(tx.effective_category)} ${Number(tx.amount).toFixed(2)}
)}
)} {editModal && trip && ( setEditModal(false)} /> )}
); }