edit for deplyment
This commit is contained in:
@ -1,6 +1,8 @@
|
|||||||
import { NextResponse } from "next/server";
|
import { NextResponse } from "next/server";
|
||||||
import { prisma } from "@/lib/prisma";
|
import { prisma } from "@/lib/prisma";
|
||||||
|
|
||||||
|
export const dynamic = "force-dynamic";
|
||||||
|
|
||||||
// GET all inventory items
|
// GET all inventory items
|
||||||
export async function GET() {
|
export async function GET() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { Printer, AlertCircle } from "lucide-react";
|
|||||||
|
|
||||||
export default function PrintPage() {
|
export default function PrintPage() {
|
||||||
const [items, setItems] = useState([]);
|
const [items, setItems] = useState([]);
|
||||||
|
const [selectedIds, setSelectedIds] = useState(new Set());
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ export default function PrintPage() {
|
|||||||
if (!res.ok) throw new Error("Failed to fetch inventory from database");
|
if (!res.ok) throw new Error("Failed to fetch inventory from database");
|
||||||
const data = await res.json();
|
const data = await res.json();
|
||||||
setItems(data);
|
setItems(data);
|
||||||
|
setSelectedIds(new Set(data.map(i => i.id)));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err.message);
|
setError(err.message);
|
||||||
} finally {
|
} finally {
|
||||||
@ -26,9 +28,24 @@ export default function PrintPage() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handlePrint = () => {
|
const handlePrint = () => {
|
||||||
|
if (selectedIds.size === 0) return alert("Please select at least one label to print.");
|
||||||
window.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 toggleAll = () => {
|
||||||
|
if (selectedIds.size === items.length) setSelectedIds(new Set());
|
||||||
|
else setSelectedIds(new Set(items.map(i => i.id)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemsToPrint = items.filter(i => selectedIds.has(i.id));
|
||||||
|
|
||||||
if (loading) return <div className="p-8 text-center">Loading inventory codes...</div>;
|
if (loading) return <div className="p-8 text-center">Loading inventory codes...</div>;
|
||||||
if (error) return <div className="p-8 text-danger">Error: {error}</div>;
|
if (error) return <div className="p-8 text-danger">Error: {error}</div>;
|
||||||
|
|
||||||
@ -64,11 +81,55 @@ export default function PrintPage() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Item Selection Table (Hidden in Print) */}
|
||||||
|
<div className="glass no-print mb-6">
|
||||||
|
<div className="flex justify-between items-center mb-4" style={{ padding: "0 1rem" }}>
|
||||||
|
<h3 className="text-muted">Select Labels to Print ({selectedIds.size} selected)</h3>
|
||||||
|
<button className="btn btn-secondary" style={{ padding: "0.25rem 0.75rem", fontSize: "0.85rem" }} onClick={toggleAll}>
|
||||||
|
{selectedIds.size === items.length ? "Deselect All" : "Select All"}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="table-container" style={{ maxHeight: "300px", overflowY: "auto" }}>
|
||||||
|
<table className="data-table">
|
||||||
|
<thead style={{ position: "sticky", top: 0, zIndex: 1, backgroundColor: "var(--bg-card)" }}>
|
||||||
|
<tr>
|
||||||
|
<th style={{ width: "50px", textAlign: "center" }}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={selectedIds.size === items.length && items.length > 0}
|
||||||
|
onChange={toggleAll}
|
||||||
|
/>
|
||||||
|
</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>QR ID</th>
|
||||||
|
<th>Category</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{items.map(item => (
|
||||||
|
<tr key={item.id} style={{ cursor: "pointer", opacity: selectedIds.has(item.id) ? 1 : 0.6 }} onClick={() => toggleSelection(item.id)}>
|
||||||
|
<td style={{ textAlign: "center" }}>
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
checked={selectedIds.has(item.id)}
|
||||||
|
onChange={() => {}} /* Handled by row click */
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td style={{ fontWeight: 500 }}>{item.name}</td>
|
||||||
|
<td><code className="text-muted">{item.qrCodeId}</code></td>
|
||||||
|
<td>{item.category || "-"}</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Printable Sheet Area */}
|
{/* Printable Sheet Area */}
|
||||||
{/* Printable Sheet Area */}
|
{/* Printable Sheet Area */}
|
||||||
{Array.from({ length: Math.ceil(items.length / 30) }, (_, pageIndex) => (
|
{Array.from({ length: Math.ceil(itemsToPrint.length / 30) }, (_, pageIndex) => (
|
||||||
<div key={pageIndex} className="print-container">
|
<div key={pageIndex} className="print-container">
|
||||||
{items.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
|
{itemsToPrint.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
|
||||||
<div key={item.id} className="label-cell">
|
<div key={item.id} className="label-cell">
|
||||||
<div className="qr-wrapper">
|
<div className="qr-wrapper">
|
||||||
<QRCode
|
<QRCode
|
||||||
|
|||||||
Reference in New Issue
Block a user