"use client"; import { useEffect, useState } from "react"; import QRCode from "react-qr-code"; import { Printer, AlertCircle, Filter, Search, Tag, CheckCircle2 } from "lucide-react"; export default function PrintPage() { const [items, setItems] = useState([]); const [selectedIds, setSelectedIds] = useState(new Set()); const [selectedCategory, setSelectedCategory] = useState(""); const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { const fetchItems = async () => { try { const res = await fetch("/api/inventory"); if (!res.ok) throw new Error("Failed to fetch inventory from database"); const data = await res.json(); setItems(data); setSelectedIds(new Set(data.map(i => i.id))); } catch (err) { setError(err.message); } finally { setLoading(false); } }; fetchItems(); }, []); const uniqueCategories = [ ...new Set(items.map(item => item.category?.trim() || "Uncategorized")) ].filter(Boolean).sort(); const filteredItems = items.filter(item => { const itemCat = item.category?.trim() || "Uncategorized"; const matchesCategory = selectedCategory === "" || itemCat === selectedCategory; const matchesSearch = searchQuery === "" || item.name?.toLowerCase().includes(searchQuery.toLowerCase()) || (item.qrCodeId && item.qrCodeId.toLowerCase().includes(searchQuery.toLowerCase())); return matchesCategory && matchesSearch; }); const isAllFilteredSelected = filteredItems.length > 0 && filteredItems.every(i => selectedIds.has(i.id)); const handlePrint = () => { if (selectedIds.size === 0) return alert("Please select at least one label to print."); window.print(); }; const toggleSelection = (id) => { const next = new Set(selectedIds); if (next.has(id)) next.delete(id); else next.add(id); setSelectedIds(next); }; const toggleFilteredAll = () => { const next = new Set(selectedIds); if (isAllFilteredSelected) { filteredItems.forEach(i => next.delete(i.id)); } else { filteredItems.forEach(i => next.add(i.id)); } setSelectedIds(next); }; const selectOnlyCurrentFiltered = () => { const next = new Set(); filteredItems.forEach(i => next.add(i.id)); setSelectedIds(next); }; const selectAll = () => { setSelectedIds(new Set(items.map(i => i.id))); }; const deselectAll = () => { setSelectedIds(new Set()); }; const itemsToPrint = items.filter(i => selectedIds.has(i.id)); const sheetCount = Math.ceil(itemsToPrint.length / 30); if (loading) return
Loading inventory codes...
; if (error) return
Error: {error}
; return ( <> {/* On-screen Controls (Hidden in Print) */}

Print QR Labels

Designed for Avery 5160 standard labels (1" x 2-5/8", 30 per sheet).

0 ? "var(--text-main)" : "var(--danger)" }}> {itemsToPrint.length} of {items.length} selected
{sheetCount} {sheetCount === 1 ? "sheet" : "sheets"} required
Printer Settings to check before printing:
  • Scale: 100% (Do not "Fit to Page")
  • Margins: Custom / None (Layout handles margins natively)
  • Paper Size: Letter (8.5x11)
  • Headers and Footers: Disable
{/* Filter and Category Selection Toolbar (Hidden in Print) */}

Filter & Select Labels

{selectedCategory && ( )}
{/* Filter Inputs */}
setSearchQuery(e.target.value)} style={{ width: "100%", paddingLeft: "36px" }} />
{/* Quick Category Badges */} {uniqueCategories.length > 1 && (
Quick Category Filter: {uniqueCategories.map(cat => { const count = items.filter(i => (i.category?.trim() || "Uncategorized") === cat).length; const isSelected = selectedCategory === cat; return ( ); })}
)}
{/* Item Selection Table (Hidden in Print) */}
Showing {filteredItems.length} of {items.length} items {selectedCategory && ` in "${selectedCategory}"`}
{filteredItems.length === 0 ? ( ) : ( filteredItems.map(item => { const isSelected = selectedIds.has(item.id); return ( toggleSelection(item.id)} > ); }) )}
Name QR ID Category Location Status
No items found matching the selected filters.
e.stopPropagation()}> toggleSelection(item.id)} /> {item.name} {item.qrCodeId} {item.category || "Uncategorized"} {item.location || "-"} {isSelected ? ( To Print ) : ( Excluded )}
{/* Printable Sheet Area */} {itemsToPrint.length === 0 ? (

No labels selected to print. Select items above to generate printable sheets.

) : ( Array.from({ length: Math.ceil(itemsToPrint.length / 30) }, (_, pageIndex) => (
{itemsToPrint.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
{item.name}
{item.qrCodeId}
{item.category &&
{item.category}
}
))}
)) )} ); }