// import React from "react"; // import { useGetInventoryStatsQuery } from "../../features/report/inventoryAPI"; // const StockBadge = ({ stock }) => { // if (stock === 0) return Out of Stock; // if (stock <= 5) return Low Stock; // return {stock}; // }; // const ProductCard = ({ product }) => ( //
//
//

{product.name}

// //
//

{product.category?.name || "Unknown Category"}

//
// ); // const InventorySection = ({ title, products }) => ( //
//

{title}

// {products.length === 0 ? ( //

No products found

// ) : ( //
// {products.map((p) => ( // // ))} //
// )} //
// ); // const InventoryReport = () => { // const { data, isLoading, isError } = useGetInventoryStatsQuery(); // if (isLoading) return
Loading inventory...
; // if (isError) return
Failed to load inventory
; // const { lowStock, outOfStock, fastMoving } = data.data; // return ( //
// // // //
// ); // }; // export default InventoryReport; // InventoryReport v2 - Editorial warm theme import React, { useState } from "react"; import { useGetInventoryStatsQuery } from "../../features/report/inventoryAPI"; const styles = ` @import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&family=Instrument+Sans:wght@400;500;600&display=swap'); :root { --bg: #f7f5f2; --surface: #ffffff; --border: #e8e4de; --border2: #f0ece6; --text: #1a1714; --muted: #9c9489; --red: #e8442a; --red-bg: #fdf1ef; --red-bdr: #f4c4bc; --amber: #d97706; --amber-bg: #fffbeb; --amber-bdr: #fde68a; --teal: #0d7a6b; --teal-bg: #f0faf8; --teal-bdr: #a7f3e4; --ink: #2d2a26; --shadow: 0 1px 3px rgba(0,0,0,0.06), 0 4px 12px rgba(0,0,0,0.04); --shadow-lg: 0 2px 8px rgba(0,0,0,0.08), 0 12px 32px rgba(0,0,0,0.06); } * { box-sizing: border-box; margin: 0; padding: 0; } .inv-root { font-family: 'Instrument Sans', sans-serif; background: var(--bg); min-height: 100vh; color: var(--text); padding: 40px 36px; } .inv-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 36px; flex-wrap: wrap; gap: 20px; } .inv-eyebrow { font-size: 0.68rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; } .inv-title { font-family: 'Fraunces', serif; font-size: 2.2rem; font-weight: 700; color: var(--ink); line-height: 1; letter-spacing: -0.02em; } .inv-summary { display: flex; gap: 10px; flex-wrap: wrap; } .inv-pill { display: flex; align-items: center; gap: 10px; padding: 10px 16px; border-radius: 12px; border: 1px solid var(--border); background: var(--surface); box-shadow: var(--shadow); } .inv-pill-icon { width: 32px; height: 32px; border-radius: 8px; display: flex; align-items: center; justify-content: center; font-size: 0.9rem; flex-shrink: 0; } .inv-pill-val { font-family: 'Fraunces', serif; font-size: 1.3rem; font-weight: 700; line-height: 1; color: var(--ink); } .inv-pill-label { font-size: 0.65rem; font-weight: 500; color: var(--muted); letter-spacing: 0.06em; text-transform: uppercase; margin-top: 2px; } .pill-total .inv-pill-icon { background: #f0ece6; } .pill-ok .inv-pill-icon { background: var(--teal-bg); } .pill-low .inv-pill-icon { background: var(--amber-bg); } .pill-out .inv-pill-icon { background: var(--red-bg); } .inv-tabs { display: flex; gap: 2px; border-bottom: 1.5px solid var(--border); margin-bottom: 28px; } .inv-tab { padding: 10px 18px; border: none; background: transparent; color: var(--muted); font-family: 'Instrument Sans', sans-serif; font-size: 0.82rem; font-weight: 600; cursor: pointer; display: flex; align-items: center; gap: 7px; transition: color 0.18s; letter-spacing: 0.01em; border-bottom: 2px solid transparent; margin-bottom: -1.5px; } .inv-tab:hover { color: var(--ink); } .inv-tab.active { color: var(--ink); border-bottom-color: var(--ink); } .inv-tab-chip { font-size: 0.6rem; font-weight: 600; padding: 2px 6px; border-radius: 99px; letter-spacing: 0.04em; } .chip-out { background: var(--red-bg); color: var(--red); } .chip-low { background: var(--amber-bg); color: var(--amber); } .chip-fast { background: var(--teal-bg); color: var(--teal); } .inv-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(270px, 1fr)); gap: 14px; } .inv-card { background: var(--surface); border: 1px solid var(--border); border-radius: 16px; padding: 20px; box-shadow: var(--shadow); transition: box-shadow 0.2s, transform 0.2s, border-color 0.2s; position: relative; overflow: hidden; animation: riseIn 0.3s both; } .inv-card:hover { box-shadow: var(--shadow-lg); transform: translateY(-2px); border-color: #d8d2ca; } @keyframes riseIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } .inv-card-stripe { position: absolute; left: 0; top: 16px; bottom: 16px; width: 3px; border-radius: 0 3px 3px 0; } .stripe-red { background: var(--red); } .stripe-amber { background: var(--amber); } .stripe-teal { background: var(--teal); } .inv-card-inner { padding-left: 14px; } .inv-card-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 8px; margin-bottom: 4px; } .inv-card-name { font-family: 'Fraunces', serif; font-size: 0.97rem; font-weight: 600; color: var(--ink); line-height: 1.3; } .inv-badge { font-size: 0.62rem; font-weight: 600; padding: 3px 8px; border-radius: 20px; white-space: nowrap; flex-shrink: 0; letter-spacing: 0.05em; text-transform: uppercase; } .badge-out { background: var(--red-bg); color: var(--red); border: 1px solid var(--red-bdr); } .badge-low { background: var(--amber-bg); color: var(--amber); border: 1px solid var(--amber-bdr); } .badge-ok { background: var(--teal-bg); color: var(--teal); border: 1px solid var(--teal-bdr); } .inv-card-meta { font-size: 0.68rem; font-weight: 500; color: var(--muted); margin-bottom: 14px; letter-spacing: 0.03em; } .inv-bar-row { display: flex; align-items: center; gap: 10px; } .inv-bar-bg { flex: 1; height: 4px; background: var(--border2); border-radius: 99px; overflow: hidden; } .inv-bar-fill { height: 100%; border-radius: 99px; transition: width 0.55s cubic-bezier(0.34,1.4,0.64,1); } .inv-bar-label { font-size: 0.7rem; font-weight: 600; color: var(--muted); min-width: 24px; text-align: right; } .inv-rank-row { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 4px; } .inv-rank-num { font-family: 'Fraunces', serif; font-size: 2rem; font-weight: 700; color: var(--border); line-height: 1; min-width: 44px; flex-shrink: 0; } .inv-purchase-tag { display: inline-flex; align-items: center; gap: 4px; font-size: 0.65rem; font-weight: 600; color: var(--teal); background: var(--teal-bg); border: 1px solid var(--teal-bdr); padding: 2px 7px; border-radius: 99px; margin-top: 3px; letter-spacing: 0.04em; text-transform: uppercase; } .inv-empty { grid-column: 1/-1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 72px 20px; gap: 10px; } .inv-empty-icon { font-size: 2.5rem; opacity: 0.25; } .inv-empty-text { font-size: 0.75rem; font-weight: 600; color: var(--muted); letter-spacing: 0.08em; text-transform: uppercase; } .inv-state { display: flex; flex-direction: column; align-items: center; justify-content: center; height: 60vh; gap: 14px; } .inv-spinner { width: 32px; height: 32px; border: 2px solid var(--border); border-top-color: var(--ink); border-radius: 50%; animation: spin 0.75s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } } .inv-state-text { font-size: 0.72rem; font-weight: 600; color: var(--muted); letter-spacing: 0.1em; text-transform: uppercase; } .inv-state-text.err { color: var(--red); } `; const shortId = (id = "") => typeof id === "string" && id.length > 8 ? id.slice(-6).toUpperCase() : String(id).toUpperCase(); const getStockPct = (stock, max = 50) => stock === 0 ? 0 : Math.min(100, Math.round((stock / max) * 100)); const StockBadge = ({ stock }) => { if (stock === 0) return No stock; if (stock <= 5) return {stock} left; return In stock; }; const StockBar = ({ stock, fillColor }) => (
{stock}
); const OutCard = ({ product, idx }) => (
{product.name}
Category · {shortId(product.category)}
); const LowCard = ({ product, idx }) => (
{product.name}
Category · {shortId(product.category)}
); const FastCard = ({ product, idx }) => (
{String(idx + 1).padStart(2, "0")}
{product.name}
↑ {product.purchaseCount ?? 0} sold
Category · {shortId(product.category)}
); const EmptyState = ({ label }) => (
No {label} products
); const TABS = [ { key: "out", label: "Out of Stock", chipClass: "chip-out" }, { key: "low", label: "Low Stock", chipClass: "chip-low" }, { key: "fast", label: "Fast Moving", chipClass: "chip-fast" }, ]; const InventoryReport = () => { const [activeTab, setActiveTab] = useState("out"); const { data, isLoading, isError } = useGetInventoryStatsQuery(); if (isLoading) return (
Loading inventory…
); if (isError) return (
Failed to load data
); const { summary, lowStock = [], outOfStock = [], fastMoving = [], } = data.data; const tabContent = { out: { products: outOfStock, Card: OutCard, emptyLabel: "out-of-stock" }, low: { products: lowStock, Card: LowCard, emptyLabel: "low-stock" }, fast: { products: fastMoving, Card: FastCard, emptyLabel: "fast-moving" }, }; const { products, Card, emptyLabel } = tabContent[activeTab]; return (
Admin · Reports
Inventory
{summary && (
📦
{summary.totalProducts}
Total
{summary.healthyStockCount}
Healthy
⚠️
{summary.lowStockCount}
Low Stock
🚫
{summary.outOfStockCount}
Out of Stock
)}
{TABS.map((tab) => ( ))}
{products.length === 0 ? ( ) : ( products.map((p, i) => ) )}
); }; export default InventoryReport;