mirror of
https://github.com/renee-png/acmcc.git
synced 2026-06-21 09:50:01 +00:00
Export the Accounting Dashboard as a vector PDF
Add a dashboard PDF generator that renders the metrics, an Income & Expenses bar chart, a Top Expenses donut, the invoices overview, and recent transactions as native PDF vector graphics + selectable text (not a screenshot), using the shared branded header/footer. Wire an "Export PDF" button into the dashboard header (association logo, ACM fallback). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
import { useState } from "react";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { accounting } from "@/lib/accountingClient";
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { useCompanyId } from "./lib/useCompanyId";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { money, fmtDate } from "./lib/format";
|
||||
import { generateDashboardPdf } from "./lib/dashboardPdf";
|
||||
import {
|
||||
Receipt, FileText, Landmark, ArrowUpRight, ArrowDownRight, Loader2,
|
||||
Receipt, FileText, Landmark, ArrowUpRight, ArrowDownRight, Loader2, FileDown,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
BarChart, Bar, XAxis, YAxis, Tooltip, ResponsiveContainer, CartesianGrid,
|
||||
@@ -19,6 +23,14 @@ export default function AccountingDashboardPage({ association }: { association?:
|
||||
const cid = companyId ?? "";
|
||||
const c = "USD";
|
||||
|
||||
const { data: assocMeta } = useQuery({
|
||||
queryKey: ["assoc-logo", associationId],
|
||||
enabled: !!associationId,
|
||||
queryFn: async () => (await supabase.from("associations").select("logo_url").eq("id", associationId!).maybeSingle()).data,
|
||||
});
|
||||
const logoUrl = (assocMeta as any)?.logo_url || null;
|
||||
const [exporting, setExporting] = useState(false);
|
||||
|
||||
const { data } = useQuery({
|
||||
queryKey: ["dashboard", cid],
|
||||
enabled: !!cid,
|
||||
@@ -160,9 +172,28 @@ export default function AccountingDashboardPage({ association }: { association?:
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Dashboard</h1>
|
||||
<p className="text-sm text-muted-foreground">{associationName}</p>
|
||||
<div className="flex items-start justify-between gap-4">
|
||||
<div>
|
||||
<h1 className="text-2xl font-semibold tracking-tight">Dashboard</h1>
|
||||
<p className="text-sm text-muted-foreground">{associationName}</p>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="gap-1"
|
||||
disabled={!data || exporting}
|
||||
onClick={async () => {
|
||||
if (!data) return;
|
||||
setExporting(true);
|
||||
try {
|
||||
await generateDashboardPdf({ companyName: associationName ?? "Company", logoUrl, currency: c, data });
|
||||
} finally {
|
||||
setExporting(false);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{exporting ? <Loader2 className="h-4 w-4 animate-spin" /> : <FileDown className="h-4 w-4" />} Export PDF
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Cash flow summary */}
|
||||
|
||||
Reference in New Issue
Block a user