diff --git a/app/dashboard/stock/page.tsx b/app/dashboard/stock/page.tsx index 7a4d073..b56706c 100644 --- a/app/dashboard/stock/page.tsx +++ b/app/dashboard/stock/page.tsx @@ -6,9 +6,27 @@ 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 } from "lucide-react"; -import { fetchProductData, updateProductStock } from "@/lib/productData"; +import { Package, RefreshCw, ChevronDown, CheckSquare, XSquare } from "lucide-react"; +import { fetchProductData, updateProductStock, saveProductData } from "@/lib/productData"; import { toast } from "sonner"; export default function StockManagementPage() { @@ -18,6 +36,9 @@ export default function StockManagementPage() { 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 @@ -117,6 +138,162 @@ export default function StockManagementPage() { }); }; + const handleToggleStockTracking = async (product: Product) => { + if (!product._id) return; + + const authToken = document.cookie + .split("; ") + .find((row) => row.startsWith("Authorization=")) + ?.split("=")[1]; + + if (!authToken) { + router.push("/login"); + return; + } + + try { + const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/products/${product._id}`; + + // Toggle the stock tracking status + const newTrackingStatus = !product.stockTracking; + + // For enabling tracking, we need to ensure there's a stock value + const stockData = { + stockTracking: newTrackingStatus, + currentStock: product.currentStock || 0, + lowStockThreshold: product.lowStockThreshold || 10, + }; + + // Update product with new tracking status + await saveProductData( + apiUrl, + stockData, + authToken, + "PUT" + ); + + // Also update stock API to ensure consistency + await updateProductStock( + product._id, + stockData, + authToken + ); + + // 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') => { + if (selectedProducts.length === 0) { + toast.error("No products selected"); + return; + } + + setBulkAction(action); + setIsConfirmDialogOpen(true); + }; + + const executeBulkAction = async () => { + const authToken = document.cookie + .split("; ") + .find((row) => row.startsWith("Authorization=")) + ?.split("=")[1]; + + if (!authToken || !bulkAction) { + setIsConfirmDialogOpen(false); + return; + } + + setLoading(true); + + try { + const isEnabling = bulkAction === 'enable'; + const updatePromises = selectedProducts.map(async (productId) => { + const product = products.find(p => p._id === productId); + if (!product) return null; + + const apiUrl = `${process.env.NEXT_PUBLIC_API_URL}/products/${productId}`; + + const stockData = { + stockTracking: isEnabling, + currentStock: product.currentStock || 0, + lowStockThreshold: product.lowStockThreshold || 10, + }; + + // Update product with new tracking status + await saveProductData( + apiUrl, + stockData, + authToken, + "PUT" + ); + + // Also update stock API to ensure consistency + await updateProductStock( + productId, + stockData, + authToken + ); + + return productId; + }); + + await Promise.all(updatePromises); + + // Update local state + setProducts(products.map(p => { + if (selectedProducts.includes(p._id as string)) { + return { + ...p, + stockTracking: isEnabling, + }; + } + return p; + })); + + setSelectedProducts([]); + toast.success(`Stock tracking ${isEnabling ? 'enabled' : 'disabled'} for ${selectedProducts.length} products`); + } catch (error) { + console.error(`Error ${bulkAction}ing stock tracking:`, error); + toast.error(`Failed to ${bulkAction} stock tracking`); + } finally { + setLoading(false); + setIsConfirmDialogOpen(false); + } + }; + + const toggleSelectProduct = (productId: string) => { + setSelectedProducts(prev => + prev.includes(productId) + ? prev.filter(id => id !== productId) + : [...prev, productId] + ); + }; + + const toggleSelectAll = () => { + if (selectedProducts.length === filteredProducts.length) { + setSelectedProducts([]); + } else { + setSelectedProducts(filteredProducts.map(p => p._id as string)); + } + }; + const getStockStatus = (product: Product) => { if (!product.stockTracking) return "Not Tracked"; @@ -150,10 +327,12 @@ export default function StockManagementPage() {

Stock Management

- +
+ +
@@ -185,7 +364,28 @@ export default function StockManagementPage() {
-

Inventory List

+
+

Inventory List

+ {selectedProducts.length > 0 && ( + + + + + + handleBulkAction('enable')}> + + Enable Tracking + + handleBulkAction('disable')}> + + Disable Tracking + + + + )} +
+ + 0 && selectedProducts.length === filteredProducts.length} + onChange={toggleSelectAll} + /> + Product Unit Status Current Stock Low Stock Threshold + Track Stock Actions {loading ? ( - + Loading... ) : filteredProducts.length > 0 ? ( filteredProducts.map((product) => ( + + toggleSelectProduct(product._id as string)} + /> + {product.name} {product.unitType} + + handleToggleStockTracking(product)} + /> + {product.stockTracking && ( editingStock[product._id as string] ? ( @@ -280,7 +503,7 @@ export default function StockManagementPage() { )) ) : ( - + No products found. @@ -289,6 +512,27 @@ export default function StockManagementPage() {
+ + + + + + {bulkAction === 'enable' ? 'Enable' : 'Disable'} Stock Tracking + + + Are you sure you want to {bulkAction === 'enable' ? 'enable' : 'disable'} stock tracking for {selectedProducts.length} selected products? + {bulkAction === 'disable' && ' This will remove any stock tracking for these products.'} + {bulkAction === 'enable' && ' This will enable stock tracking with initial values.'} + + + + Cancel + + Confirm + + + +
);