UIPackage
Menu

Framework

Change language

Boilerplate repo

Wholesale B2b Quick Order

blockcommerce

B2B wholesale bulk order matrix with volume tier pricing, case pack multipliers, and CSV SKU paste input.

Also available for Vue ->

Installation

$npx shadcn@latest add https://uipkge.dev/r/react/wholesale-b2b-quick-order.json
Named registry:npx shadcn@latest add @uipkge-react/wholesale-b2b-quick-orderInstalls to:components/blocks/

Variants

Loading interactive previews…

Props

NameType / ValuesDefaultRequired
poNumberstringoptional
accountNamestringoptional
accountTierstringoptional
tierDiscountPercentnumberoptional
paymentTermsstringoptional
freeFreightThresholdnumberoptional
initialProductsWholesaleProduct[]optional
classNamestringoptional
onSubmitOrder(payload: {optional
itemsWholesaleProduct[]required
subtotalnumberrequired
totalUnitsnumberrequired
totalCasesnumberrequired
savingsnumberrequired
onSaveTemplate(items: WholesaleProduct[]) => voidoptional
onExportCsv(items: WholesaleProduct[]) => voidoptional

Schema

Type aliases exported from this item's source. Use these to shape the data you pass in.

WholesaleProduct
interface WholesaleProduct {
  id: string
  sku: string
  name: string
  variant: string
  casePack: number
  msrpUnitPrice: number
  wholesaleUnitPrice: number
  cases: number
  availableCases: number
  image: string
  category: string
}

Files installed (1)

  • components/blocks/WholesaleB2bQuickOrder.tsx35.5 kB
    'use client'
    
    import * as React from 'react'
    import { useState, useMemo, useCallback } from 'react'
    import {
      AlertCircle,
      Bookmark,
      Building2,
      CheckCircle2,
      Download,
      FileSpreadsheet,
      Minus,
      Package,
      Plus,
      RefreshCw,
      Send,
      Layers,
      Trash2,
      TrendingDown,
      Truck,
      Upload,
      X,
    } from 'lucide-react'
    import { cn } from '@/lib/utils'
    import { Badge } from '@/components/ui/badge'
    import { Button } from '@/components/ui/button'
    import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'
    import { Input } from '@/components/ui/input'
    import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'
    import { Textarea } from '@/components/ui/textarea'
    
    export interface WholesaleProduct {
      id: string
      sku: string
      name: string
      variant: string
      casePack: number
      msrpUnitPrice: number
      wholesaleUnitPrice: number
      cases: number
      availableCases: number
      image: string
      category: string
    }
    
    export interface WholesaleB2bQuickOrderProps {
      poNumber?: string
      accountName?: string
      accountTier?: string
      tierDiscountPercent?: number
      paymentTerms?: string
      freeFreightThreshold?: number
      initialProducts?: WholesaleProduct[]
      className?: string
      onSubmitOrder?: (payload: {
        poNumber: string
        items: WholesaleProduct[]
        subtotal: number
        totalUnits: number
        totalCases: number
        savings: number
      }) => void
      onSaveTemplate?: (items: WholesaleProduct[]) => void
      onExportCsv?: (items: WholesaleProduct[]) => void
    }
    
    export const DEFAULT_WHOLESALE_PRODUCTS: WholesaleProduct[] = [
      {
        id: 'prod-1',
        sku: 'SKU-84920',
        name: 'Pro Studio Headphones',
        variant: 'Matte Black · Pro Series',
        casePack: 12,
        msrpUnitPrice: 299.0,
        wholesaleUnitPrice: 194.35,
        cases: 4,
        availableCases: 450,
        image: 'https://images.unsplash.com/photo-1505740420928-5e560c06d30e?w=300&auto=format&fit=crop&q=80',
        category: 'Audio & Acoustics',
      },
      {
        id: 'prod-2',
        sku: 'SKU-49102',
        name: 'Aero Minimalist Runner',
        variant: 'Arctic White · US 10-12 Assorted',
        casePack: 10,
        msrpUnitPrice: 140.0,
        wholesaleUnitPrice: 91.0,
        cases: 3,
        availableCases: 180,
        image: 'https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&auto=format&fit=crop&q=80',
        category: 'Footwear',
      },
      {
        id: 'prod-3',
        sku: 'SKU-77215',
        name: 'Technical Shell Parka',
        variant: 'Mineral Gray · Waterproof 3L',
        casePack: 8,
        msrpUnitPrice: 220.0,
        wholesaleUnitPrice: 143.0,
        cases: 2,
        availableCases: 95,
        image: 'https://images.unsplash.com/photo-1591047139829-d91aecb6caea?w=300&auto=format&fit=crop&q=80',
        category: 'Outerwear',
      },
      {
        id: 'prod-4',
        sku: 'SKU-10934',
        name: 'Braided USB-C Cable',
        variant: 'Space Gray · 2m 240W EPR',
        casePack: 24,
        msrpUnitPrice: 25.0,
        wholesaleUnitPrice: 16.25,
        cases: 2,
        availableCases: 620,
        image: 'https://images.unsplash.com/photo-1583863788434-e58a36330cf0?w=300&auto=format&fit=crop&q=80',
        category: 'Hardware & Cables',
      },
      {
        id: 'prod-5',
        sku: 'SKU-63821',
        name: 'Leather Cardholder',
        variant: 'Saddle Brown · Full-Grain Veg-Tan',
        casePack: 20,
        msrpUnitPrice: 50.0,
        wholesaleUnitPrice: 32.5,
        cases: 1,
        availableCases: 24,
        image: 'https://images.unsplash.com/photo-1627123424574-724758594e93?w=300&auto=format&fit=crop&q=80',
        category: 'Leather Goods',
      },
    ]
    
    const formatCurrency = (val: number) => {
      return new Intl.NumberFormat('en-US', {
        style: 'currency',
        currency: 'USD',
        minimumFractionDigits: 2,
        maximumFractionDigits: 2,
      }).format(val)
    }
    
    const formatNumber = (val: number) => {
      return new Intl.NumberFormat('en-US').format(val)
    }
    
    export function WholesaleB2bQuickOrder({
      poNumber = 'PO-2026-8841B',
      accountName = 'Northwind Retailers',
      accountTier = 'Tier 3 Wholesale Partner',
      tierDiscountPercent = 35,
      paymentTerms = 'Net 30 Invoicing',
      freeFreightThreshold = 10000,
      initialProducts,
      className,
      onSubmitOrder,
      onSaveTemplate,
      onExportCsv,
    }: WholesaleB2bQuickOrderProps) {
      const [products, setProducts] = useState<WholesaleProduct[]>(() =>
        initialProducts
          ? JSON.parse(JSON.stringify(initialProducts))
          : JSON.parse(JSON.stringify(DEFAULT_WHOLESALE_PRODUCTS)),
      )
    
      const [poRef] = useState(poNumber)
      const [showCsvBox, setShowCsvBox] = useState(false)
      const [csvPasteText, setCsvPasteText] = useState('')
      const [pasteFeedback, setPasteFeedback] = useState<{ type: 'success' | 'error'; message: string } | null>(null)
      const [templateSaved, setTemplateSaved] = useState(false)
      const [orderSubmitted, setOrderSubmitted] = useState(false)
      const [isSubmitting, setIsSubmitting] = useState(false)
    
      // Computations
      const totalCases = useMemo(() => products.reduce((acc, p) => acc + (Number(p.cases) || 0), 0), [products])
      const totalUnits = useMemo(
        () => products.reduce((acc, p) => acc + (Number(p.cases) || 0) * p.casePack, 0),
        [products],
      )
      const wholesaleSubtotal = useMemo(
        () => products.reduce((acc, p) => acc + (Number(p.cases) || 0) * p.casePack * p.wholesaleUnitPrice, 0),
        [products],
      )
      const msrpTotal = useMemo(
        () => products.reduce((acc, p) => acc + (Number(p.cases) || 0) * p.casePack * p.msrpUnitPrice, 0),
        [products],
      )
      const totalSavings = useMemo(() => Math.max(0, msrpTotal - wholesaleSubtotal), [msrpTotal, wholesaleSubtotal])
      const savingsPercent = useMemo(() => {
        if (msrpTotal <= 0) return tierDiscountPercent
        return Math.round((totalSavings / msrpTotal) * 100)
      }, [msrpTotal, totalSavings, tierDiscountPercent])
    
      const isFreeFreight = wholesaleSubtotal >= freeFreightThreshold
      const freightAmount = isFreeFreight ? 0 : 250
      const grandTotal = wholesaleSubtotal + freightAmount
    
      const nextTierTarget = 50000
      const nextTierRemaining = Math.max(0, nextTierTarget - wholesaleSubtotal)
      const tierProgressPercent = Math.min(100, Math.round((wholesaleSubtotal / nextTierTarget) * 100))
    
      // Actions
      const updateCases = useCallback((id: string, delta: number) => {
        setProducts((prev) =>
          prev.map((p) => {
            if (p.id === id) {
              const current = Number(p.cases) || 0
              const next = Math.max(0, Math.min(p.availableCases, current + delta))
              return { ...p, cases: next }
            }
            return p
          }),
        )
      }, [])
    
      const setCases = useCallback((id: string, val: string | number) => {
        setProducts((prev) =>
          prev.map((p) => {
            if (p.id === id) {
              const parsed = parseInt(String(val), 10)
              const next = isNaN(parsed) || parsed < 0 ? 0 : Math.min(p.availableCases, parsed)
              return { ...p, cases: next }
            }
            return p
          }),
        )
      }, [])
    
      const clearLine = useCallback((id: string) => {
        setProducts((prev) => prev.map((p) => (p.id === id ? { ...p, cases: 0 } : p)))
      }, [])
    
      const resetAllCases = useCallback(() => {
        setProducts((prev) => prev.map((p) => ({ ...p, cases: 0 })))
        setPasteFeedback(null)
      }, [])
    
      const restoreDefaultCases = useCallback(() => {
        setProducts(JSON.parse(JSON.stringify(DEFAULT_WHOLESALE_PRODUCTS)))
        setPasteFeedback(null)
      }, [])
    
      const applyCsvPaste = useCallback(() => {
        setPasteFeedback(null)
        if (!csvPasteText.trim()) {
          setPasteFeedback({
            type: 'error',
            message: 'Please paste SKU and case quantity rows to parse.',
          })
          return
        }
    
        const lines = csvPasteText.split(/\r?\n/)
        let updatedCount = 0
        const unknownSkus: string[] = []
    
        setProducts((prev) => {
          const cloned = prev.map((p) => ({ ...p }))
          for (const rawLine of lines) {
            const line = rawLine.trim()
            if (!line || line.startsWith('#') || line.toLowerCase().startsWith('sku')) continue
    
            const parts = line.split(/[,;\t]+/).map((s) => s.trim())
            if (parts.length >= 2) {
              const skuQuery = parts[0].toUpperCase()
              const qty = parseInt(parts[1], 10)
    
              if (!isNaN(qty)) {
                const product = cloned.find(
                  (p) => p.sku.toUpperCase() === skuQuery || p.sku.toUpperCase().includes(skuQuery),
                )
                if (product) {
                  product.cases = Math.max(0, Math.min(product.availableCases, qty))
                  updatedCount++
                } else {
                  unknownSkus.push(parts[0])
                }
              }
            }
          }
          return cloned
        })
    
        if (updatedCount > 0) {
          setPasteFeedback({
            type: 'success',
            message: `Successfully updated ${updatedCount} SKU line items in bulk matrix.${
              unknownSkus.length > 0
                ? ` Note: ${unknownSkus.length} SKU(s) not found in catalog (${unknownSkus.slice(0, 3).join(', ')}).`
                : ''
            }`,
          })
        } else {
          setPasteFeedback({
            type: 'error',
            message: 'No matching catalog SKUs found. Verify format: SKU-84920, 10',
          })
        }
      }, [csvPasteText])
    
      const loadSampleCsv = useCallback(() => {
        const sample = `SKU-84920, 8\nSKU-49102, 5\nSKU-77215, 4\nSKU-10934, 12\nSKU-63821, 6`
        setCsvPasteText(sample)
    
        // Parse sample directly
        const lines = sample.split(/\r?\n/)
        setProducts((prev) => {
          const cloned = prev.map((p) => ({ ...p }))
          let count = 0
          for (const rawLine of lines) {
            const parts = rawLine.split(/[,;\t]+/).map((s) => s.trim())
            if (parts.length >= 2) {
              const skuQuery = parts[0].toUpperCase()
              const qty = parseInt(parts[1], 10)
              const product = cloned.find((p) => p.sku.toUpperCase() === skuQuery)
              if (product && !isNaN(qty)) {
                product.cases = Math.max(0, Math.min(product.availableCases, qty))
                count++
              }
            }
          }
          return cloned
        })
        setPasteFeedback({
          type: 'success',
          message: 'Sample manifest loaded and applied to matrix (5 SKUs updated).',
        })
      }, [])
    
      const handleSaveTemplate = useCallback(() => {
        setTemplateSaved(true)
        onSaveTemplate?.(products)
        setTimeout(() => {
          setTemplateSaved(false)
        }, 4000)
      }, [products, onSaveTemplate])
    
      const handleSubmitOrder = useCallback(() => {
        if (totalCases === 0) return
        setIsSubmitting(true)
        setTimeout(() => {
          setIsSubmitting(false)
          setOrderSubmitted(true)
          onSubmitOrder?.({
            poNumber: poRef,
            items: products.filter((p) => p.cases > 0),
            subtotal: wholesaleSubtotal,
            totalUnits,
            totalCases,
            savings: totalSavings,
          })
        }, 600)
      }, [totalCases, poRef, products, wholesaleSubtotal, totalUnits, totalSavings, onSubmitOrder])
    
      const handleExportCsv = useCallback(() => {
        onExportCsv?.(products)
        const header =
          'SKU,Product Name,Variant,Case Pack Multiplier,Cases Ordered,Total Units,Wholesale Unit Price,Line Total\n'
        const rows = products
          .filter((p) => p.cases > 0)
          .map(
            (p) =>
              `"${p.sku}","${p.name}","${p.variant}",${p.casePack},${p.cases},${p.cases * p.casePack},${p.wholesaleUnitPrice},${(p.cases * p.casePack * p.wholesaleUnitPrice).toFixed(2)}`,
          )
          .join('\n')
        const csvContent = 'data:text/csv;charset=utf-8,' + encodeURIComponent(header + rows)
        const downloadLink = document.createElement('a')
        downloadLink.setAttribute('href', csvContent)
        downloadLink.setAttribute('download', `${poRef}-order-matrix.csv`)
        document.body.appendChild(downloadLink)
        downloadLink.click()
        document.body.removeChild(downloadLink)
      }, [products, onExportCsv, poRef])
    
      return (
        <div
          data-slot="wholesale-b2b-quick-order"
          className={cn('bg-background text-foreground w-full space-y-6', className)}
        >
          {/* Header & Account Info */}
          <Card className="border-border bg-card shadow-xs">
            <CardHeader className="pb-4">
              <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
                <div className="space-y-1.5">
                  <div className="flex flex-wrap items-center gap-2">
                    <div className="text-muted-foreground flex items-center gap-1.5 text-xs font-medium">
                      <Building2 className="size-3.5" />
                      <span>{accountName}</span>
                      <span>·</span>
                      <span>{accountTier}</span>
                    </div>
                    <Badge variant="outline" className="border-success/30 bg-success/10 text-success font-medium">
                      <Layers className="mr-1 size-3" />
                      {tierDiscountPercent}% Off MSRP Wholesale Tier
                    </Badge>
                  </div>
                  <CardTitle className="text-xl font-bold tracking-tight sm:text-2xl">
                    Wholesale & B2B Bulk Order Matrix
                  </CardTitle>
                  <CardDescription className="text-muted-foreground text-xs sm:text-sm">
                    Build your purchase order by entering case quantities below or pasting bulk SKU manifests with automated
                    case multipliers.
                  </CardDescription>
                </div>
    
                {/* Header Action Buttons */}
                <div className="flex flex-wrap items-center gap-2">
                  <Button
                    aria-label="Close CSV paste"
                    variant="outline"
                    size="sm"
                    className="gap-1.5 text-xs font-medium"
                    onClick={() => setShowCsvBox(!showCsvBox)}
                  >
                    <FileSpreadsheet className="size-3.5" />
                    <span>{showCsvBox ? 'Hide CSV Paste' : 'Upload CSV Order'}</span>
                  </Button>
                  <Button variant="outline" size="sm" className="gap-1.5 text-xs font-medium" onClick={handleSaveTemplate}>
                    <Bookmark className="size-3.5" />
                    <span>Save Order Template</span>
                  </Button>
                </div>
              </div>
            </CardHeader>
    
            <CardContent className="pt-0">
              {/* Account Terms & Partner Meta Strip */}
              <div className="bg-muted/40 border-border grid grid-cols-2 gap-3 rounded-lg border p-3 sm:grid-cols-4 sm:gap-4">
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">PO Reference</div>
                  <div className="font-mono text-sm font-semibold">{poRef}</div>
                </div>
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Payment Terms</div>
                  <div className="text-foreground flex items-center gap-1 text-sm font-semibold">
                    <CheckCircle2 className="text-success size-3.5" />
                    <span>{paymentTerms}</span>
                  </div>
                </div>
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Freight Status</div>
                  <div
                    className={cn('text-sm font-semibold tabular-nums', isFreeFreight ? 'text-success' : 'text-foreground')}
                  >
                    {isFreeFreight ? 'Free Ground Freight' : '$250 Standard Freight'}
                  </div>
                </div>
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Volume Tier Status</div>
                  <div className="text-foreground text-sm font-semibold">
                    Tier 3 <span className="text-muted-foreground font-normal">({tierDiscountPercent}% Margin)</span>
                  </div>
                </div>
              </div>
    
              {/* Volume Tier Margin Incentive Banner */}
              <div className="border-border bg-card/60 mt-3 rounded-lg border p-3">
                <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
                  <div className="flex items-center gap-2">
                    <TrendingDown className="text-success size-4 shrink-0" />
                    <div className="text-xs">
                      <span className="text-foreground font-semibold">Tier 4 Milestone ($50,000):</span>
                      <span className="text-muted-foreground ml-1">
                        {nextTierRemaining > 0
                          ? `Add ${formatCurrency(nextTierRemaining)} more to unlock 42% Tier 4 Enterprise Margin.`
                          : 'Tier 4 Enterprise Margin (42%) Unlocked!'}
                      </span>
                    </div>
                  </div>
                  <div className="text-muted-foreground flex items-center gap-2 text-xs">
                    <span>{tierProgressPercent}% to Tier 4</span>
                    <div className="bg-muted border-border h-2 w-24 overflow-hidden rounded-full border">
                      <div
                        className="bg-success h-full transition-[width] duration-300"
                        style={{ width: `${tierProgressPercent}%` }}
                      />
                    </div>
                  </div>
                </div>
              </div>
            </CardContent>
          </Card>
    
          {/* Template Saved Alert */}
          {templateSaved && (
            <div className="border-success/30 bg-success/10 text-success text-success flex items-center justify-between rounded-lg border p-3 text-xs sm:text-sm">
              <div className="flex items-center gap-2">
                <Bookmark className="text-success size-4 shrink-0" />
                <span>Order matrix saved as your primary template. You can re-populate this draft at any time.</span>
              </div>
              <Button
                variant="ghost"
                size="xs"
                className="text-success hover:text-success"
                aria-label="Dismiss notification"
                onClick={() => setTemplateSaved(false)}
              >
                <X className="size-3.5" />
              </Button>
            </div>
          )}
    
          {/* Order Submitted Success Alert */}
          {orderSubmitted && (
            <div className="border-success/30 bg-success/10 text-success dark:text-foreground rounded-xl border p-4 sm:p-5">
              <div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
                <div className="flex items-start gap-3">
                  <CheckCircle2 className="text-success mt-0.5 size-5 shrink-0" />
                  <div className="space-y-1">
                    <h3 className="text-sm font-semibold sm:text-base">Purchase Order {poRef} Submitted Successfully!</h3>
                    <p className="text-muted-foreground text-xs sm:text-sm">
                      Your bulk order of{' '}
                      <strong className="text-foreground">
                        {totalCases} cases ({totalUnits} units)
                      </strong>{' '}
                      totaling <strong className="text-foreground">{formatCurrency(grandTotal)}</strong> has been queued for
                      warehouse dispatch under {paymentTerms}.
                    </p>
                  </div>
                </div>
                <div className="flex items-center gap-2">
                  <Button
                    aria-label="Download attachment"
                    variant="outline"
                    size="sm"
                    className="text-xs"
                    onClick={handleExportCsv}
                  >
                    <Download className="mr-1.5 size-3.5" />
                    Download PO PDF
                  </Button>
                  <Button size="sm" className="text-xs" onClick={() => setOrderSubmitted(false)}>
                    Start New Order
                  </Button>
                </div>
              </div>
            </div>
          )}
    
          {/* Quick SKU & Quantity CSV Paste Box */}
          {showCsvBox && (
            <Card className="border-border bg-card shadow-xs transition-colors duration-200">
              <CardHeader className="pb-3">
                <div className="flex items-center justify-between">
                  <div className="flex items-center gap-2">
                    <FileSpreadsheet className="text-primary size-4" />
                    <CardTitle className="text-sm font-semibold sm:text-base">
                      Quick Paste SKU & Quantity Manifest
                    </CardTitle>
                  </div>
                  <Button
                    aria-label="Close CSV paste"
                    variant="ghost"
                    size="xs"
                    className="text-muted-foreground hover:text-foreground"
                    onClick={() => setShowCsvBox(false)}
                  >
                    <X className="size-4" />
                  </Button>
                </div>
                <CardDescription className="text-muted-foreground text-xs">
                  Paste CSV rows with SKU identifier and case quantity (one item per line, e.g.{' '}
                  <code className="bg-muted rounded px-1 font-mono">SKU-84920, 10</code>) to auto-populate matrix.
                </CardDescription>
              </CardHeader>
    
              <CardContent className="space-y-3">
                <Textarea
                  value={csvPasteText}
                  onValueChange={(val) => setCsvPasteText(val)}
                  placeholder={'SKU-84920, 8\nSKU-49102, 5\nSKU-77215, 4\nSKU-10934, 12\nSKU-63821, 6'}
                  rows={4}
                  className="font-mono text-xs"
                />
    
                <div className="flex flex-wrap items-center justify-between gap-2">
                  <div className="flex flex-wrap items-center gap-2">
                    <Button size="sm" className="text-xs font-medium" onClick={applyCsvPaste}>
                      <Upload className="mr-1.5 size-3.5" />
                      Apply SKU List to Matrix
                    </Button>
                    <Button variant="outline" size="sm" className="text-xs font-medium" onClick={loadSampleCsv}>
                      Load Sample Data
                    </Button>
                    {csvPasteText && (
                      <Button
                        variant="ghost"
                        size="sm"
                        className="text-muted-foreground text-xs"
                        onClick={() => setCsvPasteText('')}
                      >
                        Clear Input
                      </Button>
                    )}
                  </div>
                  <div className="text-muted-foreground text-xs">Supports comma, tab, and semicolon delimited lines</div>
                </div>
    
                {/* Parse Feedback Alert */}
                {pasteFeedback && (
                  <div
                    className={cn(
                      'flex items-center gap-2 rounded-lg border p-2.5 text-xs',
                      pasteFeedback.type === 'success'
                        ? 'border-success/30 bg-success/10 text-success'
                        : 'border-destructive/30 bg-destructive/10 text-destructive',
                    )}
                  >
                    {pasteFeedback.type === 'success' ? (
                      <CheckCircle2 className="text-success size-4 shrink-0" />
                    ) : (
                      <AlertCircle className="size-4 shrink-0" />
                    )}
                    <span>{pasteFeedback.message}</span>
                  </div>
                )}
              </CardContent>
            </Card>
          )}
    
          {/* Bulk SKU Matrix Table Card */}
          <Card className="border-border bg-card shadow-xs">
            <CardHeader className="border-border border-b pb-3">
              <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
                <div>
                  <CardTitle className="text-base font-semibold">Bulk SKU Order Matrix</CardTitle>
                  <CardDescription className="text-muted-foreground text-xs">
                    {products.length} wholesale catalog items available with active case multipliers.
                  </CardDescription>
                </div>
                <div className="flex items-center gap-2">
                  <Button
                    variant="outline"
                    size="xs"
                    className="text-muted-foreground text-xs"
                    onClick={restoreDefaultCases}
                  >
                    <RefreshCw className="mr-1 size-3" />
                    Reset Defaults
                  </Button>
                  <Button variant="outline" size="xs" className="text-muted-foreground text-xs" onClick={resetAllCases}>
                    <Trash2 className="mr-1 size-3" />
                    Zero All
                  </Button>
                </div>
              </div>
            </CardHeader>
    
            <CardContent className="p-0">
              <div className="overflow-x-auto">
                <Table className="w-full max-w-[760px] min-w-full">
                  <TableHeader>
                    <TableRow className="bg-muted/30">
                      <TableHead className="w-[300px] text-xs font-semibold">Product & SKU Identifier</TableHead>
                      <TableHead className="text-xs font-semibold">Case Multiplier</TableHead>
                      <TableHead className="text-xs font-semibold">Unit Price</TableHead>
                      <TableHead className="text-xs font-semibold">Case Quantity</TableHead>
                      <TableHead className="text-xs font-semibold">Availability</TableHead>
                      <TableHead className="text-right text-xs font-semibold">Line Total</TableHead>
                      <TableHead className="w-[50px]">
                        <span className="sr-only">Actions</span>
                      </TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {products.map((product) => (
                      <TableRow
                        key={product.id}
                        className={cn('transition-colors', product.cases > 0 && 'bg-primary/5 dark:bg-primary/5')}
                      >
                        {/* Product Thumbnail & Details */}
                        <TableCell className="py-3.5">
                          <div className="flex items-center gap-3">
                            <img
                              src={product.image}
                              alt={product.name}
                              className="border-border bg-muted/40 size-12 shrink-0 rounded-lg border object-cover"
                              loading="lazy"
                            />
                            <div className="min-w-0 space-y-0.5">
                              <div className="text-foreground truncate text-sm font-medium">{product.name}</div>
                              <div className="text-muted-foreground flex items-center gap-1.5 text-xs">
                                <span className="font-mono">{product.sku}</span>
                                <span>·</span>
                                <span className="truncate">{product.variant}</span>
                              </div>
                            </div>
                          </div>
                        </TableCell>
    
                        {/* Case Pack Multiplier */}
                        <TableCell className="py-3.5">
                          <div className="flex items-center gap-1.5">
                            <Package className="text-muted-foreground size-3.5" />
                            <span className="text-foreground font-mono text-xs font-medium tabular-nums">
                              {product.casePack} units / case
                            </span>
                          </div>
                        </TableCell>
    
                        {/* Pricing (MSRP vs Wholesale) */}
                        <TableCell className="py-3.5">
                          <div className="space-y-0.5">
                            <div className="text-foreground text-sm font-semibold tabular-nums">
                              {formatCurrency(product.wholesaleUnitPrice)}
                              <span className="text-muted-foreground text-xs font-normal"> wholesale</span>
                            </div>
                            <div className="text-muted-foreground flex items-center gap-1.5 text-xs">
                              <span className="tabular-nums line-through">
                                {formatCurrency(product.msrpUnitPrice)} MSRP
                              </span>
                              <span className="text-success font-medium">
                                -
                                {Math.round(
                                  ((product.msrpUnitPrice - product.wholesaleUnitPrice) / product.msrpUnitPrice) * 100,
                                )}
                                %
                              </span>
                            </div>
                          </div>
                        </TableCell>
    
                        {/* Quantity Stepper Input */}
                        <TableCell className="py-3.5">
                          <div className="space-y-1">
                            <div className="flex items-center gap-1">
                              <Button
                                aria-label="Decrease cases"
                                variant="outline"
                                size="xs"
                                className="size-7 p-0"
                                disabled={product.cases <= 0}
                                onClick={() => updateCases(product.id, -1)}
                              >
                                <Minus className="size-3" />
                              </Button>
                              <Input
                                value={product.cases}
                                type="number"
                                min={0}
                                max={product.availableCases}
                                className="h-7 w-16 text-center font-mono text-xs tabular-nums"
                                onChange={(e) => setCases(product.id, e.target.value)}
                              />
                              <Button
                                aria-label="Increase cases"
                                variant="outline"
                                size="xs"
                                className="size-7 p-0"
                                disabled={product.cases >= product.availableCases}
                                onClick={() => updateCases(product.id, 1)}
                              >
                                <Plus className="size-3" />
                              </Button>
                            </div>
                            <div className="text-muted-foreground font-mono text-xs tabular-nums">
                              {product.cases} {product.cases === 1 ? 'case' : 'cases'} ={' '}
                              <strong className="text-foreground">{product.cases * product.casePack}</strong> units
                            </div>
                          </div>
                        </TableCell>
    
                        {/* Stock Status */}
                        <TableCell className="py-3.5">
                          {product.availableCases > 50 ? (
                            <Badge
                              variant="outline"
                              className="border-success/30 bg-success/10 text-success text-xs font-medium"
                            >
                              In Stock · {formatNumber(product.availableCases)} cases
                            </Badge>
                          ) : (
                            <Badge
                              variant="outline"
                              className="border-warning/30 bg-warning/10 text-warning text-xs font-medium"
                            >
                              Low Stock · {product.availableCases} cases
                            </Badge>
                          )}
                        </TableCell>
    
                        {/* Line Total */}
                        <TableCell className="py-3.5 text-right">
                          <div className="space-y-0.5">
                            <div className="text-foreground font-mono text-sm font-bold tabular-nums">
                              {formatCurrency(product.cases * product.casePack * product.wholesaleUnitPrice)}
                            </div>
                            {product.cases > 0 ? (
                              <div className="text-success text-success font-mono text-xs tabular-nums">
                                Save{' '}
                                {formatCurrency(
                                  product.cases * product.casePack * (product.msrpUnitPrice - product.wholesaleUnitPrice),
                                )}
                              </div>
                            ) : (
                              <div className="text-muted-foreground text-xs">0 units</div>
                            )}
                          </div>
                        </TableCell>
    
                        {/* Row Clear Action */}
                        <TableCell className="py-3.5 text-center">
                          {product.cases > 0 && (
                            <Button
                              variant="ghost"
                              size="xs"
                              className="text-muted-foreground hover:text-destructive size-7 p-0"
                              title="Clear row quantity"
                              onClick={() => clearLine(product.id)}
                            >
                              <Trash2 className="size-3.5" />
                            </Button>
                          )}
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            </CardContent>
          </Card>
    
          {/* Sticky Order Summary Footer */}
          <div className="bg-card/95 border-border sticky bottom-4 z-20 rounded-xl border p-4 shadow-lg backdrop-blur-md transition-colors sm:p-5">
            <div className="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
              {/* Summary Totals Metrics */}
              <div className="grid grid-cols-2 gap-3 sm:grid-cols-4 sm:gap-6">
                {/* Total Units */}
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Total Units</div>
                  <div className="font-mono text-base font-bold tabular-nums sm:text-lg">
                    {formatNumber(totalUnits)} Units
                  </div>
                  <div className="text-muted-foreground font-mono text-xs tabular-nums">{totalCases} Cases ordered</div>
                </div>
    
                {/* Wholesale Subtotal */}
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Wholesale Subtotal</div>
                  <div className="font-mono text-base font-bold tabular-nums sm:text-lg">
                    {formatCurrency(wholesaleSubtotal)}
                  </div>
                  <div className="text-muted-foreground text-xs">MSRP {formatCurrency(msrpTotal)}</div>
                </div>
    
                {/* Tier Savings */}
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Tier Volume Savings</div>
                  <div className="text-success text-success font-mono text-base font-bold tabular-nums sm:text-lg">
                    -{formatCurrency(totalSavings)}
                  </div>
                  <div className="text-success text-xs font-medium">{savingsPercent}% Margin Savings</div>
                </div>
    
                {/* Freight & Terms */}
                <div className="space-y-0.5">
                  <div className="text-muted-foreground text-xs font-medium">Freight & Terms</div>
                  <div className="text-foreground flex items-center gap-1.5 text-xs font-semibold">
                    <Truck className="text-primary size-3.5 shrink-0" />
                    <span>{isFreeFreight ? 'Free Freight (>$10k)' : '$250 Ground'}</span>
                  </div>
                  <div className="text-muted-foreground text-xs">{paymentTerms}</div>
                </div>
              </div>
    
              {/* Submit & Secondary Actions */}
              <div className="flex flex-wrap items-center gap-2.5 pt-2 lg:pt-0">
                <Button
                  aria-label="Download attachment"
                  variant="outline"
                  size="sm"
                  className="text-xs font-medium"
                  disabled={totalCases === 0}
                  onClick={handleExportCsv}
                >
                  <Download className="mr-1.5 size-3.5" />
                  Export CSV
                </Button>
    
                <Button
                  size="default"
                  className="gap-2 text-xs font-semibold sm:text-sm"
                  disabled={totalCases === 0 || isSubmitting}
                  onClick={handleSubmitOrder}
                >
                  {!isSubmitting ? <Send className="size-4" /> : <RefreshCw className="size-4 animate-spin" />}
                  <span>{isSubmitting ? 'Processing PO...' : 'Submit Wholesale Purchase Order'}</span>
                </Button>
              </div>
            </div>
          </div>
        </div>
      )
    }
    
    export default WholesaleB2bQuickOrder
    

Raw manifest:https://uipkge.dev/r/react/wholesale-b2b-quick-order.json