"use client"; import { useState, useEffect } from "react"; import { useRouter } from "next/navigation"; import Layout from "@/components/layout/layout"; import { Button } from "@/components/ui/button"; import { Table, TableHeader, TableRow, TableHead, TableBody, TableCell } from "@/components/ui/table"; import { Input } from "@/components/ui/input"; import { Switch } from "@/components/ui/switch"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "@/components/ui/dropdown-menu"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from "@/components/ui/alert-dialog"; import { Product } from "@/models/products"; import { Package, RefreshCw, ChevronDown, CheckSquare, XSquare, Boxes } from "lucide-react"; import { clientFetch } from "@/lib/api"; import { toast } from "sonner"; interface StockData { currentStock: number; stockTracking: boolean; lowStockThreshold?: number; } export default function StockManagementPage() { const router = useRouter(); const [products, setProducts] = useState([]); const [loading, setLoading] = useState(true); const [editingStock, setEditingStock] = useState>({}); const [stockValues, setStockValues] = useState>({}); const [searchTerm, setSearchTerm] = useState(""); const [selectedProducts, setSelectedProducts] = useState([]); const [isConfirmDialogOpen, setIsConfirmDialogOpen] = useState(false); const [bulkAction, setBulkAction] = useState<'enable' | 'disable' | null>(null); useEffect(() => { const authToken = document.cookie .split("; ") .find((row) => row.startsWith("Authorization=")) ?.split("=")[1]; if (!authToken) { router.push("/login"); return; } const fetchDataAsync = async () => { try { const response = await clientFetch('api/products'); const fetchedProducts = response || []; setProducts(fetchedProducts); // Initialize stock values const initialStockValues: Record = {}; fetchedProducts.forEach((product: Product) => { if (product._id) { initialStockValues[product._id] = product.currentStock || 0; } }); setStockValues(initialStockValues); setLoading(false); } catch (error) { console.error("Error fetching products:", error); setLoading(false); } }; fetchDataAsync(); }, [router]); const handleEditStock = (productId: string) => { setEditingStock({ ...editingStock, [productId]: true, }); }; const handleSaveStock = async (product: Product) => { if (!product._id) return; try { const newStockValue = stockValues[product._id] || 0; const stockData: StockData = { currentStock: newStockValue, stockTracking: product.stockTracking || false, lowStockThreshold: product.lowStockThreshold }; await clientFetch(`api/stock/${product._id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(stockData) }); // Update local products state setProducts(products.map(p => { if (p._id === product._id) { return { ...p, currentStock: newStockValue }; } return p; })); setEditingStock({ ...editingStock, [product._id]: false, }); toast.success("Stock updated successfully"); } catch (error) { console.error("Error updating stock:", error); toast.error("Failed to update stock"); } }; const handleStockChange = (productId: string, value: number) => { setStockValues({ ...stockValues, [productId]: value, }); }; const handleToggleStockTracking = async (product: Product) => { if (!product._id) return; try { // Toggle the stock tracking status const newTrackingStatus = !product.stockTracking; // For enabling tracking, we need to ensure there's a stock value const stockData: StockData = { stockTracking: newTrackingStatus, currentStock: product.currentStock || 0, lowStockThreshold: product.lowStockThreshold || 10, }; // Update stock tracking status await clientFetch(`api/stock/${product._id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(stockData) }); // Update local state setProducts(products.map(p => { if (p._id === product._id) { return { ...p, stockTracking: newTrackingStatus, currentStock: stockData.currentStock, lowStockThreshold: stockData.lowStockThreshold, }; } return p; })); toast.success(`Stock tracking ${newTrackingStatus ? 'enabled' : 'disabled'} for ${product.name}`); } catch (error) { console.error("Error toggling stock tracking:", error); toast.error(`Failed to ${product.stockTracking ? 'disable' : 'enable'} stock tracking`); } }; const handleBulkAction = async (action: 'enable' | 'disable') => { setBulkAction(action); setIsConfirmDialogOpen(true); }; const executeBulkAction = async () => { if (!bulkAction) return; try { const productsToUpdate = products.filter(p => selectedProducts.includes(p._id || '')); await Promise.all(productsToUpdate.map(async (product) => { if (!product._id) return; const stockData: StockData = { stockTracking: bulkAction === 'enable', currentStock: product.currentStock || 0, lowStockThreshold: product.lowStockThreshold || 10, }; await clientFetch(`api/stock/${product._id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(stockData) }); })); // Update local state setProducts(products.map(p => { if (selectedProducts.includes(p._id || '')) { return { ...p, stockTracking: bulkAction === 'enable', }; } return p; })); setSelectedProducts([]); toast.success(`Stock tracking ${bulkAction}d for selected products`); } catch (error) { console.error(`Error ${bulkAction}ing stock tracking:`, error); toast.error(`Failed to ${bulkAction} stock tracking`); } setIsConfirmDialogOpen(false); setBulkAction(null); }; const toggleSelectProduct = (productId: string) => { setSelectedProducts(prev => prev.includes(productId) ? prev.filter(id => id !== productId) : [...prev, productId] ); }; const toggleSelectAll = () => { setSelectedProducts(prev => prev.length === products.length ? [] : products.map(p => p._id || '') ); }; const getStockStatus = (product: Product) => { if (!product.stockTracking) return 'Not tracked'; if (product.currentStock === undefined) return 'Unknown'; if (product.currentStock <= 0) return 'Out of stock'; if (product.lowStockThreshold && product.currentStock <= product.lowStockThreshold) return 'Low stock'; return 'In stock'; }; const filteredProducts = products.filter(product => { if (!searchTerm) return true; const searchLower = searchTerm.toLowerCase(); return ( product.name.toLowerCase().includes(searchLower) || product.description.toLowerCase().includes(searchLower) || getStockStatus(product).toLowerCase().includes(searchLower) ); }); return (

Stock Management

setSearchTerm(e.target.value)} /> {selectedProducts.length > 0 && ( handleBulkAction('enable')}> Enable Stock Tracking handleBulkAction('disable')}> Disable Stock Tracking )}
Product Stock Status Current Stock Track Stock Actions {loading ? ( Loading products... ) : filteredProducts.length === 0 ? ( No products found ) : ( filteredProducts.map((product) => ( toggleSelectProduct(product._id || '')} className="rounded border-gray-300" /> {product.name} {getStockStatus(product)} {editingStock[product._id || ''] ? (
handleStockChange(product._id || '', parseInt(e.target.value) || 0)} className="w-24" />
) : ( {product.currentStock || 0} )}
handleToggleStockTracking(product)} /> {!editingStock[product._id || ''] && ( )}
)) )}
Confirm Bulk Action Are you sure you want to {bulkAction} stock tracking for {selectedProducts.length} selected products? setBulkAction(null)}>Cancel Continue
); }