From a35e715b21be8155589d869e1d6e75a69c34c2c6 Mon Sep 17 00:00:00 2001 From: SJCoetz Date: Mon, 3 Aug 2026 18:23:11 +0200 Subject: [PATCH] =?UTF-8?q?polish(stocktake-pdf):=20zebra=20rows,=20drop?= =?UTF-8?q?=20Location,=20Target=E2=86=92Max,=20prominent=20Status,=20wide?= =?UTF-8?q?r=20Name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Visual layout cleanup on the Stocktake PDF: - Zebra-stripe alternating rows (subtle slate-50 on even rows, white on odd) so adjacent rows scan easily. - Drop the Location column — one less thing to fit on the page, and the operator has the /stock detail page for that. - Rename the Target column header to 'Max' (user-facing naming). - Move the Status column to the right edge and make it bold + colour-coded using STOCK_STATUS_STYLES[status].hex, matching the on-screen badge palette. - Widen the Name column (18%→24%) so full stock-item names read in one line for most rows. - Redistribute remaining widths so the table still totals 100% of the landscape A4 page width. Column widths now: SKU 10 / Name 24 / Supplier 18 / Current 9 / Min 8 / Max 9 / Status 16 / spacer 6 (= 100%). Co-authored-by: Orca --- src/lib/pdf/stock-item-stocktake-document.tsx | 69 +++++++++++-------- 1 file changed, 42 insertions(+), 27 deletions(-) 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} );