Adds complete initial codebase for the RJ Bulk Supplies fuel delivery backoffice: - Authentication pages and protected route layouts - Customer, supplier, fuel purchase, and delivery note management - Custom reporting and customer statement sending tools - Full UI component library and Tailwind styling - Server actions, API routes, and PocketBase integration - Development scripts and project configuration updates - Updated README and package metadata
119 lines
4.8 KiB
TypeScript
119 lines
4.8 KiB
TypeScript
"use client";
|
||
|
||
import { useState } from "react";
|
||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||
import { Button } from "@/components/ui/button";
|
||
import { Label } from "@/components/ui/label";
|
||
import { Select } from "@/components/ui/select";
|
||
import { Checkbox } from "@/components/ui/checkbox";
|
||
import { Input } from "@/components/ui/input";
|
||
import { Eye } from "lucide-react";
|
||
import { REPORT_TYPES, type ReportType } from "@/lib/pdf/reports";
|
||
|
||
export function CustomReportsForm() {
|
||
const [type, setType] = useState<ReportType>("customer-delivery");
|
||
const [range, setRange] = useState("this-month");
|
||
const [start, setStart] = useState("");
|
||
const [end, setEnd] = useState("");
|
||
const [sort, setSort] = useState("date");
|
||
const [includePricing, setIncludePricing] = useState(true);
|
||
|
||
const previewUrl = `/api/reports/preview?type=${type}&range=${range}${range === "custom" ? `&start=${start}&end=${end}` : ""}&include_pricing=${includePricing}`;
|
||
|
||
return (
|
||
<div className="grid gap-6 lg:grid-cols-3">
|
||
<Card className="lg:col-span-1">
|
||
<CardHeader>
|
||
<CardTitle>Build report</CardTitle>
|
||
<CardDescription>Choose type and date range</CardDescription>
|
||
</CardHeader>
|
||
<CardContent className="space-y-4">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="report-type">Report type</Label>
|
||
<Select
|
||
id="report-type"
|
||
value={type}
|
||
onChange={(e) => setType(e.target.value as ReportType)}
|
||
options={REPORT_TYPES}
|
||
/>
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="range">Date range</Label>
|
||
<Select
|
||
id="range"
|
||
value={range}
|
||
onChange={(e) => setRange(e.target.value)}
|
||
options={[
|
||
{ value: "this-month", label: "This Month" },
|
||
{ value: "last-month", label: "Last Month" },
|
||
{ value: "custom", label: "Custom" },
|
||
]}
|
||
/>
|
||
</div>
|
||
{range === "custom" && (
|
||
<div className="grid grid-cols-2 gap-2">
|
||
<div className="space-y-2">
|
||
<Label htmlFor="start">From</Label>
|
||
<Input id="start" type="date" value={start} onChange={(e) => setStart(e.target.value)} />
|
||
</div>
|
||
<div className="space-y-2">
|
||
<Label htmlFor="end">To</Label>
|
||
<Input id="end" type="date" value={end} onChange={(e) => setEnd(e.target.value)} />
|
||
</div>
|
||
</div>
|
||
)}
|
||
<div className="space-y-2">
|
||
<Label htmlFor="sort">Sort by</Label>
|
||
<Select
|
||
id="sort"
|
||
value={sort}
|
||
onChange={(e) => setSort(e.target.value)}
|
||
options={[
|
||
{ value: "date", label: "Date" },
|
||
{ value: "date-desc", label: "Date (newest first)" },
|
||
{ value: "qty", label: "Quantity" },
|
||
{ value: "value", label: "Value" },
|
||
]}
|
||
/>
|
||
</div>
|
||
<div className="flex items-center gap-2">
|
||
<Checkbox id="pricing" checked={includePricing} onCheckedChange={(v) => setIncludePricing(!!v)} />
|
||
<Label htmlFor="pricing">Include pricing</Label>
|
||
</div>
|
||
<Button asChild className="w-full">
|
||
<a href={previewUrl} target="_blank" rel="noopener">
|
||
<Eye className="h-4 w-4" /> Preview report
|
||
</a>
|
||
</Button>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card className="lg:col-span-2">
|
||
<CardHeader>
|
||
<CardTitle>Report types</CardTitle>
|
||
<CardDescription>What each one does</CardDescription>
|
||
</CardHeader>
|
||
<CardContent>
|
||
<ul className="space-y-3 text-sm">
|
||
{REPORT_TYPES.map((t) => (
|
||
<li key={t.value} className="rounded-md border p-3">
|
||
<div className="font-medium">{t.label}</div>
|
||
<div className="text-xs text-muted-foreground">{REPORT_DESCRIPTIONS[t.value]}</div>
|
||
</li>
|
||
))}
|
||
</ul>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
const REPORT_DESCRIPTIONS: Record<ReportType, string> = {
|
||
"customer-delivery": "Group deliveries by customer, with subtotals and grand total per customer.",
|
||
"vehicle-delivery": "Group deliveries by vehicle registration, useful for fleet tracking.",
|
||
"daily-summary": "One row per day with total quantity and value.",
|
||
"detailed-delivery": "Flat list of every delivery note in the date range.",
|
||
"tank-delivery": "Group deliveries by plant/dispensing location (tank).",
|
||
"purchase-summary": "Aggregated fuel purchases by month with supplier breakdown.",
|
||
"inventory": "Current inventory balance (purchases − deliveries) with cost and value totals.",
|
||
};
|