diff --git a/app/add/page.js b/app/add/page.js
index c6cb083..1e7f828 100644
--- a/app/add/page.js
+++ b/app/add/page.js
@@ -5,7 +5,7 @@ import { Upload, Plus, AlertCircle, CheckCircle2 } from "lucide-react";
import * as xlsx from "xlsx";
export default function AddImportPage() {
- const [formData, setFormData] = useState({ name: "", qrCodeId: "", quantity: 0, price: 0.0, category: "", description: "" });
+ const [formData, setFormData] = useState({ name: "", qrCodeId: "", quantity: 0, price: 0.0, category: "", location: "", description: "" });
const [loading, setLoading] = useState(false);
const [status, setStatus] = useState({ type: "", message: "" });
const [importStats, setImportStats] = useState(null);
@@ -37,7 +37,7 @@ export default function AddImportPage() {
if (!res.ok) throw new Error(data.error || "Failed to create item");
setStatus({ type: "success", message: `Successfully added ${data.name}.` });
- setFormData({ name: "", qrCodeId: "", quantity: 0, price: 0.0, category: "", description: "" });
+ setFormData({ name: "", qrCodeId: "", quantity: 0, price: 0.0, category: "", location: "", description: "" });
} catch (err) {
setStatus({ type: "error", message: err.message });
} finally {
@@ -81,6 +81,7 @@ export default function AddImportPage() {
quantity: parseInt(normalizedRow["quantity"] || normalizedRow["qty"]) || 0,
price: parseFloat(normalizedRow["price"] || normalizedRow["cost"]) || 0.0,
category: normalizedRow["category"] || "",
+ location: normalizedRow["location"] || normalizedRow["bin"] || normalizedRow["aisle"] || "",
description: normalizedRow["description"] || "",
};
@@ -147,9 +148,15 @@ export default function AddImportPage() {
-
diff --git a/app/api/inventory/route.js b/app/api/inventory/route.js
index 8771f10..773df2b 100644
--- a/app/api/inventory/route.js
+++ b/app/api/inventory/route.js
@@ -17,7 +17,7 @@ export async function GET() {
export async function POST(req) {
try {
const body = await req.json();
- const { qrCodeId, name, quantity, price, category, description } = body;
+ const { qrCodeId, name, quantity, price, category, location, description } = body;
const newItem = await prisma.inventoryItem.upsert({
where: { qrCodeId },
@@ -26,6 +26,7 @@ export async function POST(req) {
quantity: quantity || 0,
price: price || 0.0,
category: category || "",
+ location: location || "",
description: description || "",
},
create: {
@@ -34,6 +35,7 @@ export async function POST(req) {
quantity: quantity || 0,
price: price || 0.0,
category: category || "",
+ location: location || "",
description: description || "",
},
});
diff --git a/app/page.js b/app/page.js
index 520a4c9..1b7bc35 100644
--- a/app/page.js
+++ b/app/page.js
@@ -11,6 +11,11 @@ export default function Dashboard() {
const [editingId, setEditingId] = useState(null);
const [editForm, setEditForm] = useState({});
+ const [searchQuery, setSearchQuery] = useState("");
+ const [selectedCategory, setSelectedCategory] = useState("");
+ const [currentPage, setCurrentPage] = useState(1);
+ const itemsPerPage = 10;
+
const fetchItems = async () => {
setLoading(true);
setError(null);
@@ -46,16 +51,18 @@ export default function Dashboard() {
const startEdit = (item) => {
setEditingId(item.id);
- setEditForm({ name: item.name, category: item.category || "", quantity: item.quantity, price: item.price });
+ setEditForm({ name: item.name, category: item.category || "", location: item.location || "", quantity: item.quantity, price: item.price });
};
const saveEdit = async (id) => {
try {
+ const parsedQty = parseInt(editForm.quantity, 10);
const payload = {
id,
name: editForm.name,
category: editForm.category,
- quantity: parseInt(editForm.quantity) || 0,
+ location: editForm.location,
+ quantity: isNaN(parsedQty) ? 0 : parsedQty,
price: parseFloat(editForm.price) || 0.0,
};
@@ -78,15 +85,35 @@ export default function Dashboard() {
};
+ // Filter and Paginate Items
+ useEffect(() => {
+ setCurrentPage(1);
+ }, [searchQuery, selectedCategory]);
+
+ const uniqueCategories = [...new Set(items.map(item => item.category?.trim() || "Uncategorized"))].filter(c => c).sort();
+
+ const filteredItems = items.filter(item => {
+ const matchesSearch = item.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ item.qrCodeId.toLowerCase().includes(searchQuery.toLowerCase());
+ const matchesCategory = selectedCategory === "" || (item.category?.trim() || "Uncategorized") === selectedCategory;
+ return matchesSearch && matchesCategory;
+ });
+
+ const totalPages = Math.max(1, Math.ceil(filteredItems.length / itemsPerPage));
+ const startIndex = (currentPage - 1) * itemsPerPage;
+ const paginatedItems = filteredItems.slice(startIndex, startIndex + itemsPerPage);
+
const handleExport = () => {
- if (items.length === 0) return alert("No items to export");
- const ws = xlsx.utils.json_to_sheet(items.map(i => ({
+ if (filteredItems.length === 0) return alert("No items to export");
+ const ws = xlsx.utils.json_to_sheet(filteredItems.map(i => ({
"QR ID": i.qrCodeId,
"Name": i.name,
"Quantity": i.quantity,
"Price": i.price,
"Category": i.category || "",
- "Description": i.description || ""
+ "Location": i.location || "",
+ "Description": i.description || "",
+ "Last Updated": i.updatedAt ? new Date(i.updatedAt).toLocaleString() : ""
})));
const wb = xlsx.utils.book_new();
xlsx.utils.book_append_sheet(wb, ws, "Inventory");
@@ -133,19 +160,49 @@ export default function Dashboard() {
) : (
+
+ setSearchQuery(e.target.value)}
+ style={{ flex: 1 }}
+ />
+
+
+
| Name |
QR ID |
Category |
+ Location |
Quantity |
Price |
+ Last Updated |
Actions |
- {items.map(item => (
+ {paginatedItems.length === 0 ? (
+
+ |
+ No items match your filters.
+ |
+
+ ) : paginatedItems.map(item => (
|
{editingId === item.id ? (
@@ -158,6 +215,11 @@ export default function Dashboard() {
setEditForm({...editForm, category: e.target.value})} />
) : (item.category || "-")}
|
+
+ {editingId === item.id ? (
+ setEditForm({...editForm, location: e.target.value})} />
+ ) : (item.location || "-")}
+ |
{editingId === item.id ? (
setEditForm({...editForm, quantity: e.target.value})} />
@@ -172,6 +234,9 @@ export default function Dashboard() {
setEditForm({...editForm, price: e.target.value})} />
) : `$${Number(item.price).toFixed(2)}`}
|
+
+ {item.updatedAt ? new Date(item.updatedAt).toLocaleDateString() + " " + new Date(item.updatedAt).toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'}) : "N/A"}
+ |
{editingId === item.id ? (
@@ -199,6 +264,33 @@ export default function Dashboard() {
))}
|
+
+ {filteredItems.length > 0 && (
+
+
+ Showing {startIndex + 1} to {Math.min(startIndex + itemsPerPage, filteredItems.length)} of {filteredItems.length} entries
+
+
+
+
+ Page {currentPage} of {totalPages}
+
+
+
+
+ )}
)}
diff --git a/app/print/page.js b/app/print/page.js
index 8bdab6b..43f4d16 100644
--- a/app/print/page.js
+++ b/app/print/page.js
@@ -65,24 +65,28 @@ export default function PrintPage() {
{/* Printable Sheet Area */}
-
- {items.map((item, index) => (
-
-
-
+ {/* Printable Sheet Area */}
+ {Array.from({ length: Math.ceil(items.length / 30) }, (_, pageIndex) => (
+
+ {items.slice(pageIndex * 30, (pageIndex + 1) * 30).map((item) => (
+
+
+
+
+
+
{item.name}
+
{item.qrCodeId}
+
-
-
{item.name}
-
{item.qrCodeId}
-
-
- ))}
-
+ ))}
+
+ ))}
+