init
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { cache } from "react";
|
||||
import type { Metadata } from "next";
|
||||
import { readBillPayload } from "../../../lib/bills";
|
||||
import { BILL_NOT_FOUND, formatBillDate, parseBill, type BillView } from "../../../lib/bill-view";
|
||||
import { money } from "../../../lib/money";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const loadBill = cache(async (token: string): Promise<BillView | null> => {
|
||||
const raw = await readBillPayload(token);
|
||||
if (!raw) return null;
|
||||
return parseBill(raw);
|
||||
});
|
||||
|
||||
export async function generateMetadata({
|
||||
params,
|
||||
}: {
|
||||
params: Promise<{ token: string }>;
|
||||
}): Promise<Metadata> {
|
||||
const { token } = await params;
|
||||
const bill = await loadBill(token);
|
||||
if (!bill) return { title: "100kmph invoice" };
|
||||
return { title: `${bill.number || "Invoice"} · 100kmph` };
|
||||
}
|
||||
|
||||
export default async function BillPage({ params }: { params: Promise<{ token: string }> }) {
|
||||
const { token } = await params;
|
||||
const bill = await loadBill(token);
|
||||
if (!bill) return <main id="bill">{BILL_NOT_FOUND}</main>;
|
||||
|
||||
const when = formatBillDate(bill.createdAt);
|
||||
return (
|
||||
<main id="bill">
|
||||
<h1>{bill.shopName || "100kmph"}</h1>
|
||||
<p className="muted">{bill.address}</p>
|
||||
<p className="muted">{bill.phone ? `Ph: ${bill.phone}` : ""}</p>
|
||||
<hr />
|
||||
<p>
|
||||
<strong>Invoice {bill.number}</strong>
|
||||
<br />
|
||||
{when}
|
||||
</p>
|
||||
<p>
|
||||
Customer: {bill.customerName || "-"}
|
||||
<br />
|
||||
Phone: {bill.customerPhone || "-"}
|
||||
{bill.vehicleReg ? (
|
||||
<>
|
||||
<br />
|
||||
Vehicle: {bill.vehicleReg} {bill.vehicleModel}
|
||||
</>
|
||||
) : null}
|
||||
</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Item</th>
|
||||
<th className="num">Qty</th>
|
||||
<th className="num">Rate</th>
|
||||
<th className="num">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{bill.lines.map((line, index) => (
|
||||
<tr key={index}>
|
||||
<td>{line.description}</td>
|
||||
<td className="num">{line.qty ?? ""}</td>
|
||||
<td className="num">{money(line.unitPrice)}</td>
|
||||
<td className="num">{money(line.lineTotal)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<p className="total">Total {money(bill.total)}</p>
|
||||
<p>Paid by: {bill.paymentMethod.toUpperCase()}</p>
|
||||
<p className="foot">Digital invoice from 100kmph. You can print this page if you need paper.</p>
|
||||
</main>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user