diff --git a/src/lib/pdf/stock-item-stocktake-document.tsx b/src/lib/pdf/stock-item-stocktake-document.tsx index c93d53b..a53ccc9 100644 --- a/src/lib/pdf/stock-item-stocktake-document.tsx +++ b/src/lib/pdf/stock-item-stocktake-document.tsx @@ -8,6 +8,9 @@ export interface StockItemStocktakeDocumentProps { generatedAtIso: string; } +const ZEBRA_EVEN = "#f8fafc"; // slate-50 — subtle alternating row tint +const ZEBRA_ODD = "#ffffff"; + const styles = StyleSheet.create({ page: { padding: 28, fontSize: 9, fontFamily: "Helvetica" }, header: { marginBottom: 18 }, @@ -30,29 +33,40 @@ const styles = StyleSheet.create({ paddingVertical: 4, paddingHorizontal: 4, }, + trEven: { + flexDirection: "row", + backgroundColor: ZEBRA_EVEN, + borderBottomWidth: 0.5, + borderBottomColor: "#ddd", + paddingVertical: 4, + paddingHorizontal: 4, + }, td: { fontSize: 9 }, tdRight: { fontSize: 9, textAlign: "right" }, - // Columns mirror the /stock page table so a printed copy feels - // familiar to the operator. Landscape A4 gives 8 columns room to - // breathe — same allocation as the stock-orders list PDF. - cSku: { width: "9%" }, - cName: { width: "18%" }, - cSupplier: { width: "16%" }, - cCurrent: { width: "8%" }, - cMin: { width: "7%" }, - cTarget: { width: "8%" }, - cLocation: { width: "14%" }, - cStatus: { width: "12%" }, - spacer: { width: "8%" }, + // Status is rendered with the status colour (from STOCK_STATUS_STYLES) + // and bold, so it pops as a right-side summary of the row. + tdStatus: { fontSize: 9, fontFamily: "Helvetica-Bold" }, + // Columns mirror the on-screen /stock table — Location dropped, Target + // renamed to "Max". Name and Status widened so the row reads at a + // glance. Landscape A4 has plenty of horizontal room. + cSku: { width: "10%" }, + cName: { width: "24%" }, + cSupplier: { width: "18%" }, + cCurrent: { width: "9%" }, + cMin: { width: "8%" }, + cMax: { width: "9%" }, + cStatus: { width: "16%" }, + spacer: { width: "6%" }, empty: { marginTop: 24, color: "#666", fontSize: 10, textAlign: "center" }, }); /** * Stock list PDF — landscape A4, every active stock item in a * table sorted by name. Columns mirror the on-screen /stock table - * (SKU, Name, Supplier, Current, Min, Target, Location, Status) so - * the printed copy is recognisable. The Status column uses the same - * `getStockStatus` derivation as the on-screen badge. + * minus Location, with Target renamed to "Max" and the Name column + * widened. Rows alternate subtle zebra tinting so adjacent rows are + * easy to scan; the Status column sits at the right edge and is + * bold + colour-coded against the on-screen badge palette. */ export function StockItemStocktakeDocument({ items, @@ -80,10 +94,9 @@ export function StockItemStocktakeDocument({ Min - - Target + + Max - Location Status @@ -92,21 +105,22 @@ export function StockItemStocktakeDocument({ No active stock items. ) : ( - {items.map((item) => { + {items.map((item, idx) => { const status = getStockStatus( item.current_qty, item.min_qty, item.is_active, ); - const statusLabel = STOCK_STATUS_STYLES[status].label; + const statusStyle = STOCK_STATUS_STYLES[status]; const currentQty = Number(item.current_qty ?? 0); const minQty = Number(item.min_qty ?? 0); - const targetQty = + const maxQty = item.target_qty !== undefined && item.target_qty !== null ? Number(item.target_qty) : null; + const rowStyle = idx % 2 === 0 ? styles.trEven : styles.tr; return ( - + {item.sku || "—"} {item.name} @@ -117,13 +131,14 @@ export function StockItemStocktakeDocument({ {item.unit ? ` ${item.unit}` : ""} {minQty} - - {targetQty !== null && targetQty > 0 ? targetQty : "—"} + + {maxQty !== null && maxQty > 0 ? maxQty : "—"} - - {item.location || "—"} + + {statusStyle.label} - {statusLabel} );