refactor: extract useInventoryFilter hook from inventory/page.tsx

This commit is contained in:
2026-04-19 12:29:22 +03:00
parent 0e89059cac
commit cf45437bb0
2 changed files with 63 additions and 18 deletions

View File

@@ -6,6 +6,7 @@ import { inventoryApi } from '@/lib/api';
import PageShell from '@/components/PageShell';
import Scanner from '@/components/Scanner';
import StatCard from '@/components/StatCard';
import { useInventoryFilter } from '@/hooks/useInventoryFilter';
import { toast } from 'react-hot-toast';
import {
Package,
@@ -39,9 +40,20 @@ export default function InventoryPage() {
const [mounted, setMounted] = useState(false);
const [inventory, setInventory] = useState<Item[]>([]);
const [stats, setStats] = useState<any>(null);
const [expandedCategory, setExpandedCategory] = useState<string | null>(null);
const [searchQuery, setSearchQuery] = useState('');
const [currentUser, setCurrentUser] = useState<any | null>(null);
const {
searchQuery,
setSearchQuery,
expandedCategory,
setExpandedCategory,
boxSearchQuery,
setBoxSearchQuery,
categories,
filteredCategories,
getFilteredItems,
getFilteredBoxes
} = useInventoryFilter(inventory);
// Stock Adjustment State
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
@@ -66,7 +78,6 @@ export default function InventoryPage() {
// Box Manager State
const [showBoxManager, setShowBoxManager] = useState(false);
const [selectedBoxLabel, setSelectedBoxLabel] = useState<string | null>(null);
const [boxSearchQuery, setBoxSearchQuery] = useState('');
useEffect(() => {
setMounted(true);
@@ -225,13 +236,6 @@ export default function InventoryPage() {
}
}, [inventory]);
// Group items by category
const categories = Array.from(new Set(inventory.map(i => i.category)));
const filteredCategories = categories.filter(c =>
c.toLowerCase().includes(searchQuery.toLowerCase()) ||
inventory.some(i => i.category === c && i.name.toLowerCase().includes(searchQuery.toLowerCase()))
);
// Extract unique item types and box labels for suggestions
const existingTypes = Array.from(new Set(inventory.map(i => i.type).filter(Boolean))).sort() as string[];
const existingBoxes = Array.from(new Set(inventory.map(i => i.box_label).filter(Boolean))).sort() as string[];
@@ -340,10 +344,7 @@ export default function InventoryPage() {
{expandedCategory === cat && (
<div className="p-4 pt-0 space-y-2 animate-in slide-in-from-top-4 duration-300">
<div className="h-px bg-slate-800/50 mb-4 mx-2" />
{inventory
.filter(i => i.category === cat)
.filter(i => i.name.toLowerCase().includes(searchQuery.toLowerCase()))
.map(item => (
{getFilteredItems(cat).map(item => (
<div
key={item.id}
onClick={() => setSelectedItem(item)}
@@ -717,7 +718,7 @@ export default function InventoryPage() {
</div>
<div className="flex-1 overflow-y-auto p-6 space-y-4 pt-4">
{existingBoxes.filter(b => b.toLowerCase().includes(boxSearchQuery.toLowerCase())).length === 0 ? (
{getFilteredBoxes(existingBoxes).length === 0 ? (
<div className="py-20 text-center space-y-4 opacity-40">
<Package size={48} className="mx-auto" />
<p className="font-bold">{existingBoxes.length === 0 ? 'No box labels defined yet.' : 'No matching boxes found.'}</p>
@@ -725,9 +726,7 @@ export default function InventoryPage() {
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 pb-4">
{existingBoxes
.filter(box => box.toLowerCase().includes(boxSearchQuery.toLowerCase()))
.map(box => {
{getFilteredBoxes(existingBoxes).map(box => {
const itemCount = inventory.filter(i => i.box_label === box).length;
return (
<div key={box} className="bg-background/50 border border-slate-800/60 p-5 rounded-3xl flex flex-col gap-4 group hover:border-primary/40 transition-all">

View File

@@ -0,0 +1,46 @@
import { useState, useMemo } from 'react';
import { Item } from '@/lib/db';
export function useInventoryFilter(inventory: Item[]) {
const [searchQuery, setSearchQuery] = useState('');
const [expandedCategory, setExpandedCategory] = useState<string | null>(null);
const [boxSearchQuery, setBoxSearchQuery] = useState('');
// Get unique categories from inventory
const categories = useMemo(
() => Array.from(new Set(inventory.map(i => i.category))),
[inventory]
);
// Filter categories based on search query
const filteredCategories = useMemo(
() => categories.filter(c =>
c.toLowerCase().includes(searchQuery.toLowerCase()) ||
inventory.some(i => i.category === c && i.name.toLowerCase().includes(searchQuery.toLowerCase()))
),
[categories, inventory, searchQuery]
);
// Get filtered items within a specific category
const getFilteredItems = (category: string) =>
inventory
.filter(i => i.category === category)
.filter(i => i.name.toLowerCase().includes(searchQuery.toLowerCase()));
// Get filtered boxes based on search
const getFilteredBoxes = (boxes: string[]) =>
boxes.filter(b => b.toLowerCase().includes(boxSearchQuery.toLowerCase()));
return {
searchQuery,
setSearchQuery,
expandedCategory,
setExpandedCategory,
boxSearchQuery,
setBoxSearchQuery,
categories,
filteredCategories,
getFilteredItems,
getFilteredBoxes
};
}