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 PageShell from '@/components/PageShell';
|
||||||
import Scanner from '@/components/Scanner';
|
import Scanner from '@/components/Scanner';
|
||||||
import StatCard from '@/components/StatCard';
|
import StatCard from '@/components/StatCard';
|
||||||
|
import { useInventoryFilter } from '@/hooks/useInventoryFilter';
|
||||||
import { toast } from 'react-hot-toast';
|
import { toast } from 'react-hot-toast';
|
||||||
import {
|
import {
|
||||||
Package,
|
Package,
|
||||||
@@ -39,9 +40,20 @@ export default function InventoryPage() {
|
|||||||
const [mounted, setMounted] = useState(false);
|
const [mounted, setMounted] = useState(false);
|
||||||
const [inventory, setInventory] = useState<Item[]>([]);
|
const [inventory, setInventory] = useState<Item[]>([]);
|
||||||
const [stats, setStats] = useState<any>(null);
|
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 [currentUser, setCurrentUser] = useState<any | null>(null);
|
||||||
|
|
||||||
|
const {
|
||||||
|
searchQuery,
|
||||||
|
setSearchQuery,
|
||||||
|
expandedCategory,
|
||||||
|
setExpandedCategory,
|
||||||
|
boxSearchQuery,
|
||||||
|
setBoxSearchQuery,
|
||||||
|
categories,
|
||||||
|
filteredCategories,
|
||||||
|
getFilteredItems,
|
||||||
|
getFilteredBoxes
|
||||||
|
} = useInventoryFilter(inventory);
|
||||||
|
|
||||||
// Stock Adjustment State
|
// Stock Adjustment State
|
||||||
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
|
const [selectedItem, setSelectedItem] = useState<Item | null>(null);
|
||||||
@@ -66,7 +78,6 @@ export default function InventoryPage() {
|
|||||||
// Box Manager State
|
// Box Manager State
|
||||||
const [showBoxManager, setShowBoxManager] = useState(false);
|
const [showBoxManager, setShowBoxManager] = useState(false);
|
||||||
const [selectedBoxLabel, setSelectedBoxLabel] = useState<string | null>(null);
|
const [selectedBoxLabel, setSelectedBoxLabel] = useState<string | null>(null);
|
||||||
const [boxSearchQuery, setBoxSearchQuery] = useState('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMounted(true);
|
setMounted(true);
|
||||||
@@ -225,13 +236,6 @@ export default function InventoryPage() {
|
|||||||
}
|
}
|
||||||
}, [inventory]);
|
}, [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
|
// 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 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[];
|
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 && (
|
{expandedCategory === cat && (
|
||||||
<div className="p-4 pt-0 space-y-2 animate-in slide-in-from-top-4 duration-300">
|
<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" />
|
<div className="h-px bg-slate-800/50 mb-4 mx-2" />
|
||||||
{inventory
|
{getFilteredItems(cat).map(item => (
|
||||||
.filter(i => i.category === cat)
|
|
||||||
.filter(i => i.name.toLowerCase().includes(searchQuery.toLowerCase()))
|
|
||||||
.map(item => (
|
|
||||||
<div
|
<div
|
||||||
key={item.id}
|
key={item.id}
|
||||||
onClick={() => setSelectedItem(item)}
|
onClick={() => setSelectedItem(item)}
|
||||||
@@ -717,7 +718,7 @@ export default function InventoryPage() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 overflow-y-auto p-6 space-y-4 pt-4">
|
<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">
|
<div className="py-20 text-center space-y-4 opacity-40">
|
||||||
<Package size={48} className="mx-auto" />
|
<Package size={48} className="mx-auto" />
|
||||||
<p className="font-bold">{existingBoxes.length === 0 ? 'No box labels defined yet.' : 'No matching boxes found.'}</p>
|
<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>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 pb-4">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3 pb-4">
|
||||||
{existingBoxes
|
{getFilteredBoxes(existingBoxes).map(box => {
|
||||||
.filter(box => box.toLowerCase().includes(boxSearchQuery.toLowerCase()))
|
|
||||||
.map(box => {
|
|
||||||
const itemCount = inventory.filter(i => i.box_label === box).length;
|
const itemCount = inventory.filter(i => i.box_label === box).length;
|
||||||
return (
|
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">
|
<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