refactor: extract useInventoryFilter hook from inventory/page.tsx
This commit is contained in:
@@ -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">
|
||||
|
||||
46
frontend/hooks/useInventoryFilter.ts
Normal file
46
frontend/hooks/useInventoryFilter.ts
Normal 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
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user