health-petal/apps/pharmanager/src/routes/billing/$id.tsx
2026-05-24 15:12:43 +05:30

122 lines
5.5 KiB
TypeScript

import { createFileRoute } from "@tanstack/react-router";
import { ReceiptText, User, Clock, DollarSign } from "lucide-react";
import { DetailRow, BackLink, EmptyState } from "#/components/ui";
import { useGetBillById } from "shared-react";
export const Route = createFileRoute("/billing/$id")({
component: BillDetailsPage,
staticData: {
title: "Bill Details",
subtitle: "Loading...",
},
});
function BillDetailsPage() {
const { id } = Route.useParams();
const billId = Number(id);
const { data: bill, isLoading } = useGetBillById(billId);
if (isLoading) return <div className="text-sm text-slate-600 py-8">Loading bill...</div>;
if (!bill) {
return (
<EmptyState
icon={ReceiptText}
title="Bill not found"
description="The bill you're looking for doesn't exist."
actionLabel="Back to Billing"
actionTo="/billing"
/>
);
}
const d = new Date(bill.created_at);
const dateStr = d.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric", hour: "2-digit", minute: "2-digit" });
return (
<div>
<BackLink to="/billing" label="Billing" />
<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-6 mb-5 flex justify-between items-start gap-5 max-w-[960px]">
<div>
<div className="text-[22px] font-bold text-blue-600">{bill.bill_no}</div>
<div className="text-[13px] text-slate-500 mt-1">{dateStr}</div>
<div className="mt-3 flex items-center gap-2 text-sm text-slate-700">
<User className="w-4 h-4" />
{bill.customer_name ? `${bill.customer_name} (${bill.customer_mobile})` : bill.customer_mobile}
</div>
</div>
<div className="text-right shrink-0">
<div className="text-[28px] font-bold text-emerald-600">{bill.total.toFixed(2)}</div>
<span className="inline-block mt-1.5 px-2.5 py-0.5 rounded-full text-xs font-semibold bg-emerald-50 text-emerald-600">Completed</span>
</div>
</div>
<div className="grid grid-cols-2 gap-5 max-w-[960px] mb-5">
<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5">
<h3 className="flex items-center gap-1.5 text-xs font-semibold text-slate-600 uppercase tracking-wider mb-3">
<Clock className="w-[14px] h-[14px]" />Timings & Info
</h3>
<div className="grid grid-cols-2 gap-2 text-[13px]">
<span className="text-slate-500">Generated</span><span className="font-medium">{dateStr}</span>
<span className="text-slate-500">Items</span><span className="font-medium">{bill.items.length}</span>
</div>
</div>
<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5">
<h3 className="flex items-center gap-1.5 text-xs font-semibold text-slate-600 uppercase tracking-wider mb-3">
<DollarSign className="w-[14px] h-[14px]" />Payment Summary
</h3>
<div className="grid grid-cols-2 gap-2 text-[13px]">
<span className="text-slate-500">Subtotal</span><span className="font-medium text-right">{bill.subtotal.toFixed(2)}</span>
<span className="text-slate-500">Tax ({bill.tax_rate}%)</span><span className="font-medium text-right">{bill.tax.toFixed(2)}</span>
<span className="text-emerald-600">Discount</span><span className="font-medium text-right text-emerald-600">{bill.discount_percent}%</span>
<span className="text-slate-900 font-semibold border-t border-slate-200 pt-1.5">Total</span>
<span className="font-bold text-right text-blue-600 border-t border-slate-200 pt-1.5">{bill.total.toFixed(2)}</span>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow-[0_0_0_1px_rgba(0,0,0,0.06),0_1px_2px_rgba(0,0,0,0.04)] p-5 max-w-[960px]">
<h3 className="flex items-center gap-1.5 text-xs font-semibold text-slate-600 uppercase tracking-wider mb-4">
<ReceiptText className="w-[14px] h-[14px]" />Bill Items
</h3>
<div className="overflow-x-auto">
<table className="w-full text-sm">
<thead>
<tr className="text-[11px] font-semibold text-slate-600 uppercase tracking-wider border-b border-slate-200">
<th className="text-left pb-2 px-2.5">Product</th>
<th className="text-center pb-2 px-2.5">Strips</th>
<th className="text-center pb-2 px-2.5">Loose</th>
<th className="text-left pb-2 px-2.5">Price</th>
<th className="text-right pb-2 px-2.5">Total</th>
</tr>
</thead>
<tbody>
{bill.items.map((item) => (
<tr key={item.id} className="border-b border-slate-100">
<td className="py-2.5 px-2.5">
<div className="font-semibold text-[13px]">{item.product_name}</div>
{item.brand && <div className="text-xs text-slate-500">{item.brand}</div>}
</td>
<td className="py-2.5 px-2.5 text-center">{item.strips}</td>
<td className="py-2.5 px-2.5 text-center">{item.loose}</td>
<td className="py-2.5 px-2.5">
{item.original_price !== item.selling_price ? (
<div className="flex items-center gap-1.5">
<span className="text-xs text-slate-400 line-through">{item.original_price.toFixed(2)}</span>
<span className="font-semibold text-emerald-600">{item.selling_price.toFixed(2)}</span>
</div>
) : (
<span className="font-semibold">{item.selling_price.toFixed(2)}</span>
)}
</td>
<td className="py-2.5 px-2.5 text-right font-semibold">{item.total.toFixed(2)}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
);
}