WFDASH-WEBAPP/reports/intel-mockup.html

383 lines
22 KiB
HTML
Raw Normal View History

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Item Intel Mockup · Q202608094</title>
<style>
:root {
--bg: #f8fafc;
--panel: #ffffff;
--border: #e2e8f0;
--text: #0f172a;
--muted: #64748b;
--muted-2: #94a3b8;
--accent: #4f46e5;
--accent-soft: #eef2ff;
--green: #16a34a;
--green-soft: #dcfce7;
--amber: #d97706;
--amber-soft: #fef3c7;
--red: #dc2626;
--red-soft: #fee2e2;
--mono: ui-monospace, SFMono-Regular, Menlo, monospace;
}
* { box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
margin: 0;
background: var(--bg);
color: var(--text);
line-height: 1.45;
}
.page { max-width: 880px; margin: 0 auto; padding: 24px 16px 80px; }
.header { display: flex; align-items: baseline; gap: 12px; margin-bottom: 6px; }
.header h1 { font-size: 18px; font-weight: 600; margin: 0; }
.badge {
background: var(--accent-soft); color: var(--accent);
font-size: 10px; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.05em; padding: 2px 8px; border-radius: 999px;
}
.sub { color: var(--muted); font-size: 13px; margin-bottom: 24px; }
.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 0; }
.tab {
padding: 8px 14px; font-size: 13px; font-weight: 500;
border: 1px solid transparent; border-bottom: none;
border-radius: 6px 6px 0 0; cursor: pointer; color: var(--muted); background: transparent;
}
.tab[aria-selected="true"] {
color: var(--accent); background: var(--panel);
border-color: var(--border); margin-bottom: -1px;
}
.popover {
background: var(--panel); border: 1px solid var(--border);
border-radius: 0 8px 8px 8px; padding: 16px;
box-shadow: 0 4px 12px rgba(15, 23, 42, 0.06);
}
.item-header {
display: flex; align-items: baseline; justify-content: space-between;
gap: 12px; padding-bottom: 12px;
border-bottom: 1px dashed var(--border); margin-bottom: 14px;
}
.item-desc { font-weight: 600; font-size: 14px; }
.item-meta { font-size: 11px; color: var(--muted); font-family: var(--mono); }
.summary {
background: var(--accent-soft); color: var(--accent);
padding: 8px 12px; border-radius: 6px; font-size: 12px; margin-bottom: 16px;
}
.summary b { color: var(--text); }
.section { margin-bottom: 18px; }
.section:last-child { margin-bottom: 0; }
.section-title {
display: flex; align-items: center; justify-content: space-between;
font-size: 10px; font-weight: 700; text-transform: uppercase;
letter-spacing: 0.06em; color: var(--muted); margin-bottom: 6px;
}
.section-title .pill {
background: var(--border); color: var(--text);
padding: 1px 6px; border-radius: 999px;
font-size: 10px; font-weight: 600; text-transform: none; letter-spacing: 0;
}
table { width: 100%; border-collapse: collapse; font-size: 12px; }
th, td {
text-align: left; padding: 6px 8px;
border-bottom: 1px solid var(--border); vertical-align: middle;
}
th {
font-weight: 600; color: var(--muted); font-size: 10px;
text-transform: uppercase; letter-spacing: 0.04em; background: #f1f5f9;
}
tr:last-child td { border-bottom: none; }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
td.dim { color: var(--muted); }
td.mono { font-family: var(--mono); font-size: 11px; }
.status {
display: inline-block; font-size: 10px; font-weight: 700;
padding: 1px 6px; border-radius: 4px;
text-transform: uppercase; letter-spacing: 0.04em;
}
.status.in_stock { background: var(--green-soft); color: var(--green); }
.status.low { background: var(--amber-soft); color: var(--amber); }
.status.out { background: var(--red-soft); color: var(--red); }
.status.received { background: var(--green-soft); color: var(--green); }
.status.sent { background: var(--accent-soft); color: var(--accent); }
.status.delivered { background: var(--green-soft); color: var(--green); }
.status.pending { background: var(--border); color: var(--muted); }
.status.problem { background: var(--red-soft); color: var(--red); }
.status.emailed { background: var(--accent-soft); color: var(--accent); }
.status.approved { background: var(--green-soft); color: var(--green); }
.btn {
border: 1px solid var(--border); background: var(--panel);
color: var(--text); font-size: 11px; font-weight: 500;
padding: 3px 8px; border-radius: 4px; cursor: pointer; margin-right: 4px;
}
.btn:hover { background: var(--accent-soft); border-color: var(--accent); color: var(--accent); }
.btn.primary { background: var(--accent); color: white; border-color: var(--accent); }
.btn.primary:hover { background: #4338ca; }
.empty { color: var(--muted-2); font-style: italic; padding: 8px 0; font-size: 12px; }
.footer-note {
margin-top: 24px; padding: 12px 16px;
background: #f1f5f9; border-radius: 6px;
font-size: 11px; color: var(--muted);
}
.legend { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; font-size: 11px; color: var(--muted); }
.legend span::before { content: "•"; margin-right: 4px; color: var(--accent); }
.panel-hidden { display: none; }
</style>
</head>
<body>
<div class="page">
<div class="header">
<h1>Item Intel Mockup</h1>
<span class="badge">Q202608094</span>
</div>
<div class="sub">
Click a tab to swap the quote item. This is the popover that would render when you click the
ⓘ icon next to a line item. Limits: stock ≤3, supplier history = last per unique supplier,
price list ≤5, recent quote ≤2, recent order ≤2.
</div>
<div class="tabs" role="tablist">
<button class="tab" aria-selected="true" data-tab="0">M20 x 30 set screw black<span class="count" style="font-size:10px;color:var(--muted-2);margin-left:4px;">qty 399</span></button>
<button class="tab" aria-selected="false" data-tab="1">SAE 50 - 20L<span class="count" style="font-size:10px;color:var(--muted-2);margin-left:4px;">qty 2</span></button>
<button class="tab" aria-selected="false" data-tab="2">Silicone sealant clear<span class="count" style="font-size:10px;color:var(--muted-2);margin-left:4px;">qty 12</span></button>
</div>
<!-- Item 0 — M20 set screw -->
<div class="popover" data-panel="0">
<div class="item-header">
<div>
<div class="item-desc">M20 x 30 set screw black</div>
<div class="item-meta">quote_item · rar7m1d0m6jgeb5 · qty 399 · no SKU</div>
</div>
</div>
<div class="summary">
out of stock · bought from <b>3 suppliers</b> — top: Gracal R 6.22 (3d ago) · last quoted R 12.20 14d ago (Q000032) · last order 11d ago
</div>
<div class="section">
<div class="section-title">Stock List <span class="pill">3 rows</span></div>
<table>
<thead><tr><th>SKU</th><th>Name</th><th class="num">Qty</th><th class="num">Cost</th><th>Supplier</th><th>Status</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">PKS11</td><td>M20 X 75 SET SCREW ZPL</td><td class="num">0</td><td class="num dim">—</td><td>Pro-Tech Fasteners</td><td><span class="status out">out</span></td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">PKS12</td><td>M20 X 80 SET SCREW ZPL</td><td class="num">0</td><td class="num dim">—</td><td>Pro-Tech Fasteners</td><td><span class="status out">out</span></td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">PKS06</td><td>M12 X 40 SET SCREW ZPL</td><td class="num">0</td><td class="num dim">—</td><td>NSS Fastners</td><td><span class="status out">out</span></td><td><button class="btn">copy</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Supplier History <span class="pill">3 rows · 3 suppliers</span></div>
<table>
<thead><tr><th>Supplier</th><th class="num">Days ago</th><th class="num">Last cost</th><th class="num">×bought</th><th>Last PO</th><th></th></tr></thead>
<tbody>
<tr><td>Gracal Trading</td><td class="num">3</td><td class="num">R 6.22</td><td class="num">4</td><td class="mono">PO26080706STK</td><td><button class="btn primary">apply</button></td></tr>
<tr><td>Pro-Tech Fasteners</td><td class="num">3</td><td class="num">R 8.92</td><td class="num">2</td><td class="mono">PO26080705STK</td><td><button class="btn primary">apply</button></td></tr>
<tr><td>NSS Fastners</td><td class="num">3</td><td class="num">R 1.75</td><td class="num">2</td><td class="mono">PO26080704STK</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Price List <span class="pill">0 rows</span></div>
<div class="empty">No exact price list match — only M20 threaded rods exist, no M20 set screws.</div>
</div>
<div class="section">
<div class="section-title">Recent Quote <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Quote</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Cost</th><th class="num">Sell</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">Q000032</td><td class="num">14</td><td class="num">100</td><td class="num">R 10.00</td><td class="num">R 12.20</td><td>M20 x 30 DAVE</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">Q000121</td><td class="num">14</td><td class="num">160</td><td class="num">R 10.96</td><td class="num">R 14.25</td><td>M20 X 60MM HT SET SCREW HDG</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Recent Order <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Order</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Sell</th><th>Status</th><th>Supplier</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">1114938-OR</td><td class="num">11</td><td class="num">50</td><td class="num">R 2.12</td><td><span class="status delivered">delivered</span></td><td>NSS Fastners</td><td>M12 X 30 SET SCREW</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">WYNAND06/08/2026</td><td class="num">3</td><td class="num">50</td><td class="num">R 8.26</td><td><span class="status pending">collection_pool</span></td><td>NSS Fastners</td><td>M20 X 130 SET SCREW GR10.9 BLK</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
</div>
<!-- Item 1 — SAE 50 -->
<div class="popover panel-hidden" data-panel="1">
<div class="item-header">
<div>
<div class="item-desc">SAE 50 - 20L</div>
<div class="item-meta">quote_item · 0zbkoxfdlz0t7mh · qty 2 · no SKU</div>
</div>
</div>
<div class="summary">
in stock · <b>qty 2 @ R 990</b> (AFRIQ LUBE) · on price list · last order 11d ago
</div>
<div class="section">
<div class="section-title">Stock List <span class="pill">3 rows</span></div>
<table>
<thead><tr><th>SKU</th><th>Name</th><th class="num">Qty</th><th class="num">Cost</th><th>Supplier</th><th>Status</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">SAE50SF/CF4-20</td><td>SAE 50 - 20L</td><td class="num">2</td><td class="num">R 990.00</td><td>AFRIQ LUBE</td><td><span class="status in_stock">in stock</span></td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">SAE40SFCF4-20</td><td>SAE 40 - 20L</td><td class="num">2</td><td class="num">R 963.00</td><td>AFRIQ LUBE</td><td><span class="status in_stock">in stock</span></td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">HYD68-20</td><td>HYDRAULIC 68 - 20L</td><td class="num">16</td><td class="num">R 748.00</td><td>AFRIQ LUBE</td><td><span class="status in_stock">in stock</span></td><td><button class="btn">copy</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Supplier History <span class="pill">1 row · 1 supplier</span></div>
<table>
<thead><tr><th>Supplier</th><th class="num">Days ago</th><th class="num">Last cost</th><th class="num">×bought</th><th>Last PO</th><th></th></tr></thead>
<tbody>
<tr><td>AFRIQ LUBE AND SERVICES CC</td><td class="num">10</td><td class="num">R 990.00</td><td class="num">5</td><td class="mono">PO26073109STK</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Price List <span class="pill">5 rows</span></div>
<table>
<thead><tr><th>SKU</th><th>Description</th><th class="num">Cost</th><th class="num">Sell</th><th>Supplier</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">AFRIQ-...SAE_50_SF_CF4-20LT</td><td>SAE 50 SF/CF4 - 20 LT</td><td class="num">R 879.00</td><td class="num">R 879.00</td><td>AFRIQ LUBE</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">AFRIQ-...SAE_50_SG_CF4-20LT</td><td>SAE 50 SG/CF4 - 20 LT</td><td class="num">R 859.00</td><td class="num">R 859.00</td><td>AFRIQ LUBE</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">AFRIQ-...SAE_50_SF_CF4-20X500ML</td><td>SAE 50 SF/CF4 - 20X500ML</td><td class="num">R 566.00</td><td class="num">R 566.00</td><td>AFRIQ LUBE</td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">AFRIQ-...SAE_50_SF_CF4-12X1LT</td><td>SAE 50 SF/CF4 - 12X1LT</td><td class="num">R 586.00</td><td class="num">R 586.00</td><td>AFRIQ LUBE</td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">AFRIQ-...SAE_50_SF_CF4-210LT</td><td>SAE 50 SF/CF4 - 210 LT</td><td class="num">R 8,594.00</td><td class="num">R 8,594.00</td><td>AFRIQ LUBE</td><td><button class="btn">copy</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Recent Quote <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Quote</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Cost</th><th class="num">Sell</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">RFQ000125</td><td class="num">14</td><td class="num">1</td><td class="num">R 1,687.24</td><td class="num">R 2,277.77</td><td>20L</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">Q007498</td><td class="num">14</td><td class="num">6</td><td class="num">R 434.00</td><td class="num">R 607.60</td><td>ANTIFREEZE 50% 20L</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Recent Order <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Order</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Sell</th><th>Status</th><th>Supplier</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">PO055945</td><td class="num">11</td><td class="num">2</td><td class="num">R 585.90</td><td><span class="status delivered">delivered</span></td><td>AFRIQ LUBE</td><td>20L ANTIFREEZE COOLANT — ALL SEASON 50%</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">13/05/2026 Johan</td><td class="num">11</td><td class="num">20</td><td class="num">R 597.50</td><td><span class="status delivered">delivered</span></td><td>AFRIQ LUBE</td><td>Antifreeze 50% All season 20L</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
</div>
<!-- Item 2 — Silicone clear -->
<div class="popover panel-hidden" data-panel="2">
<div class="item-header">
<div>
<div class="item-desc">Silicone sealant clear</div>
<div class="item-meta">quote_item · h5szkwdxs1u2quk · qty 12 · no SKU</div>
</div>
</div>
<div class="summary">
in stock · <b>qty 24 @ R 32.50</b> (Matus) · last quoted R 45.10 14d ago (Q000782, approved) · last order 11d ago
</div>
<div class="section">
<div class="section-title">Stock List <span class="pill">3 rows</span></div>
<table>
<thead><tr><th>SKU</th><th>Name</th><th class="num">Qty</th><th class="num">Cost</th><th>Supplier</th><th>Status</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">SKU2-FE6EB3</td><td>SILICONE CLEAR</td><td class="num">24</td><td class="num">R 32.50</td><td>Matus - Impumemelo</td><td><span class="status in_stock">in stock</span></td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">SKU3-27031C</td><td>SILICONE WHITE</td><td class="num">24</td><td class="num">R 32.50</td><td>Matus - Impumemelo</td><td><span class="status in_stock">in stock</span></td><td><button class="btn">copy</button></td></tr>
<tr><td class="mono">SKU4-9FED0D</td><td>SILICONE HIGH HEAT H/R</td><td class="num">24</td><td class="num">R 106.50</td><td>Matus - Impumemelo</td><td><span class="status in_stock">in stock</span></td><td><button class="btn">copy</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Supplier History <span class="pill">1 row · 1 supplier</span></div>
<table>
<thead><tr><th>Supplier</th><th class="num">Days ago</th><th class="num">Last cost</th><th class="num">×bought</th><th>Last PO</th><th></th></tr></thead>
<tbody>
<tr><td>Matus - Impumemelo</td><td class="num">10</td><td class="num">R 32.50</td><td class="num">4</td><td class="mono">PO26073110STK</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Price List <span class="pill">0 rows</span></div>
<div class="empty">No price list match — catalogue only has silicone spray / Renov'Plastique, no clear sealant.</div>
</div>
<div class="section">
<div class="section-title">Recent Quote <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Quote</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Cost</th><th class="num">Sell</th><th>Status</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">Q000782</td><td class="num">14</td><td class="num">4</td><td class="num">R 30.45</td><td class="num">R 45.10</td><td><span class="status approved">approved</span></td><td>Clear silicone</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">Q000783</td><td class="num">14</td><td class="num">4</td><td class="num">R 30.45</td><td class="num">R 45.10</td><td><span class="status approved">approved</span></td><td>Clear silicone</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
<div class="section">
<div class="section-title">Recent Order <span class="pill">2 rows</span></div>
<table>
<thead><tr><th>Order</th><th class="num">Days ago</th><th class="num">Qty</th><th class="num">Sell</th><th>Status</th><th>Supplier</th><th>Description</th><th></th></tr></thead>
<tbody>
<tr><td class="mono">MSP17006</td><td class="num">11</td><td class="num">8</td><td class="num">R 41.11</td><td><span class="status delivered">delivered</span></td><td>Fowkes Bros</td><td>SILICONE SEALANT CLEAR 260ML</td><td><button class="btn primary">apply</button></td></tr>
<tr><td class="mono">MSP17141</td><td class="num">11</td><td class="num">10</td><td class="num">R 40.50</td><td><span class="status delivered">delivered</span></td><td>CNL - IN STOCK</td><td>SERMAT Silicone Sealant Clear</td><td><button class="btn primary">apply</button></td></tr>
</tbody>
</table>
</div>
</div>
<div class="footer-note">
<strong>What this is.</strong> Static HTML mockup — the actual popover that will render in the app
uses the same JSON shape from <span class="mono">reports/item-intel-q202608094.json</span>.
<br><br>
<strong>Per-section limits (your spec):</strong>
<div class="legend">
<span><b>Stock List</b> — ≤ 3 fuzzy-matched stock items (sorted by description-fuzzy score)</span>
<span><b>Supplier History</b> — last order at every unique supplier, derived from <span class="mono">stock_purchase_items</span> joined to <span class="mono">stock_purchases</span></span>
<span><b>Price List</b> — ≤ 5 matches ranked by overlapScore against <span class="mono">search_text</span></span>
<span><b>Recent Quote</b> — ≤ 2 most recent matches</span>
<span><b>Recent Order</b> — ≤ 2 most recent matches</span>
</div>
<br>
<strong>Buttons:</strong>
<div class="legend">
<span><b>copy</b> — puts cost / supplier / date on the clipboard for manual paste</span>
<span><b>apply</b> — PATCHes the item's cost_price / selling_price / supplier / pricing_notes from this row</span>
</div>
<br>
<strong>Placement:</strong> Option A — replace the ⓘ popover content on the existing
<span class="mono">AiItemHistoryTrigger</span> (already wired into quote detail, approvals,
sprint, and orders sprint pages).
</div>
</div>
<script>
const tabs = document.querySelectorAll(".tab");
const panels = document.querySelectorAll("[data-panel]");
tabs.forEach((t) => {
t.addEventListener("click", () => {
const idx = t.dataset.tab;
tabs.forEach((x) => x.setAttribute("aria-selected", x === t ? "true" : "false"));
panels.forEach((p) => p.classList.toggle("panel-hidden", p.dataset.panel !== idx));
});
});
</script>
</body>
</html>