- Engine: Add ppa_revenue_cr, mcp_revenue_cr, tariff, units to PnLRow - Engine: Split PPA vs MCP revenue in P&L computation - Web: Collapsible rows for PPA/MCP Revenue and Opex - Web: Highlighted rows (Total Revenue, EBITDA, EBIT, PBT, PAT) - Web: Units above Tariff in breakdown, bg-blue-50 highlight - Fix sticky column z-index for horizontal scroll - CLAUDE.md: Add project documentation Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
"use client";
|
||
|
||
import { Suspense } from "react";
|
||
import { useSearchParams, useRouter } from "next/navigation";
|
||
import { useQuery } from "@tanstack/react-query";
|
||
import { listScenarios } from "@/lib/api";
|
||
import { ScenarioCompare } from "@/components/ScenarioCompare";
|
||
import { Button } from "@/components/ui/button";
|
||
|
||
function CompareContent() {
|
||
const params = useSearchParams();
|
||
const router = useRouter();
|
||
const ids = params.getAll("id");
|
||
|
||
const { data: scenarios } = useQuery({
|
||
queryKey: ["scenarios"],
|
||
queryFn: listScenarios,
|
||
});
|
||
|
||
const successScenarios = (scenarios ?? []).filter((s) => s.status === "success");
|
||
|
||
const nameMap = Object.fromEntries(
|
||
(scenarios ?? []).map((s) => [s.id, s.name])
|
||
);
|
||
|
||
function toggleId(id: string) {
|
||
const next = ids.includes(id) ? ids.filter((x) => x !== id) : [...ids, id];
|
||
const qs = next.map((x) => `id=${x}`).join("&");
|
||
router.push(qs ? `/compare?${qs}` : "/compare");
|
||
}
|
||
|
||
return (
|
||
<main className="flex-1 container mx-auto px-4 py-8 max-w-5xl">
|
||
<div className="mb-6 flex items-center gap-4">
|
||
<Button variant="ghost" size="sm" onClick={() => router.push("/")}>
|
||
← Back
|
||
</Button>
|
||
<h1 className="text-xl font-bold">Compare Scenarios</h1>
|
||
</div>
|
||
|
||
<div className="mb-6">
|
||
<p className="text-sm text-muted-foreground mb-3">
|
||
Select 2–4 completed scenarios to compare side-by-side.
|
||
</p>
|
||
<div className="flex flex-wrap gap-2">
|
||
{successScenarios.map((s) => (
|
||
<button
|
||
key={s.id}
|
||
onClick={() => toggleId(s.id)}
|
||
className={`px-3 py-1.5 rounded-full text-sm border transition-colors ${
|
||
ids.includes(s.id)
|
||
? "bg-primary text-primary-foreground border-primary"
|
||
: "border-muted-foreground/40 text-muted-foreground hover:border-foreground"
|
||
}`}
|
||
>
|
||
{s.name}
|
||
</button>
|
||
))}
|
||
</div>
|
||
</div>
|
||
|
||
{ids.length >= 2 ? (
|
||
<ScenarioCompare scenarioIds={ids} scenarioNames={nameMap} />
|
||
) : (
|
||
<div className="text-center text-muted-foreground py-16 border rounded-lg text-sm">
|
||
Select at least 2 scenarios above to see the comparison table.
|
||
</div>
|
||
)}
|
||
</main>
|
||
);
|
||
}
|
||
|
||
export default function ComparePage() {
|
||
return (
|
||
<Suspense fallback={<div className="flex-1 flex items-center justify-center text-muted-foreground">Loading…</div>}>
|
||
<CompareContent />
|
||
</Suspense>
|
||
);
|
||
}
|