Update product-table.tsx

This commit is contained in:
g
2026-01-12 06:54:28 +00:00
parent 211cdc71f9
commit 7c7db0fc09

View File

@@ -1,4 +1,3 @@
import {
Table,
TableBody,
TableCell,
@@ -14,11 +13,15 @@ import {
AlertCircle,
Calculator,
Copy,
PackageOffset,
Archive
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Product } from "@/models/products";
import { Badge } from "@/components/ui/badge";
import { Switch } from "@/components/ui/switch";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { motion, AnimatePresence } from "framer-motion";
interface ProductTableProps {
products: Product[];
@@ -68,35 +71,53 @@ const ProductTable = ({
}
};
const renderProductRow = (product: Product, isDisabled: boolean = false) => (
<TableRow
const renderProductRow = (product: Product, index: number, isDisabled: boolean = false) => (
<motion.tr
key={product._id}
className={`transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70 ${isDisabled ? "opacity-60" : ""}`}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.2, delay: index * 0.05 }}
className={`group hover:bg-muted/40 border-b border-border/50 transition-colors ${isDisabled ? "opacity-60 bg-muted/20" : ""}`}
>
<TableCell>
<div className="font-medium truncate max-w-[180px]">{product.name}</div>
<div className="hidden sm:block text-sm text-muted-foreground mt-1">
<TableCell className="font-medium">
<div className="flex items-center gap-2">
<div className="h-8 w-8 rounded bg-muted/50 flex items-center justify-center text-muted-foreground">
{product.image ? (
<img src={product.image} alt={product.name} className="h-full w-full object-cover rounded" />
) : (
<span className="text-xs font-bold">{product.name.charAt(0).toUpperCase()}</span>
)}
</div>
<div>
<div className="truncate max-w-[180px]">{product.name}</div>
<div className="sm:hidden text-xs text-muted-foreground">
{getCategoryNameById(product.category)}
</div>
</div>
</div>
</TableCell>
<TableCell className="hidden sm:table-cell text-center">
<Badge variant="outline" className="font-normal bg-background/50">
{getCategoryNameById(product.category)}
</Badge>
</TableCell>
<TableCell className="hidden md:table-cell text-center">
<TableCell className="hidden md:table-cell text-center text-muted-foreground text-sm">
{product.unitType}
</TableCell>
<TableCell className="text-center">
{product.stockTracking ? (
<div className="flex items-center justify-center gap-1">
<div className="flex items-center justify-center gap-1.5">
{getStockIcon(product)}
<span className="text-sm">
{product.currentStock !== undefined ? product.currentStock : 0}{" "}
{product.unitType}
<span className={`text-sm font-medium ${product.stockStatus === 'out_of_stock' ? 'text-destructive' :
product.stockStatus === 'low_stock' ? 'text-amber-500' : 'text-foreground'
}`}>
{product.currentStock !== undefined ? product.currentStock : 0}
</span>
</div>
) : (
<Badge variant="outline" className="text-xs">
Not Tracked
<Badge variant="secondary" className="text-[10px] h-5 px-1.5 text-muted-foreground bg-muted/50">
Unlimited
</Badge>
)}
</TableCell>
@@ -106,17 +127,19 @@ const ProductTable = ({
onCheckedChange={(checked) =>
onToggleEnabled(product._id as string, checked)
}
className="data-[state=checked]:bg-primary"
/>
</TableCell>
<TableCell className="text-right flex justify-end space-x-1">
<TableCell className="text-right">
<div className="flex items-center justify-end gap-1">
{onProfitAnalysis && (
<Button
variant="ghost"
size="sm"
size="icon"
onClick={() =>
onProfitAnalysis(product._id as string, product.name)
}
className="text-green-600 hover:text-green-700 hover:bg-green-50 dark:hover:bg-green-950/20"
className="h-8 w-8 text-emerald-500 hover:text-emerald-600 hover:bg-emerald-500/10"
title="Profit Analysis"
>
<Calculator className="h-4 w-4" />
@@ -125,9 +148,9 @@ const ProductTable = ({
{onClone && (
<Button
variant="ghost"
size="sm"
size="icon"
onClick={() => onClone(product)}
className="text-blue-600 hover:text-blue-700 hover:bg-blue-50 dark:hover:bg-blue-950/20"
className="h-8 w-8 text-blue-500 hover:text-blue-600 hover:bg-blue-500/10"
title="Clone Listing"
>
<Copy className="h-4 w-4" />
@@ -135,28 +158,30 @@ const ProductTable = ({
)}
<Button
variant="ghost"
size="sm"
size="icon"
onClick={() => onEdit(product)}
className="h-8 w-8 text-muted-foreground hover:text-foreground"
title="Edit Product"
>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
size="icon"
onClick={() => onDelete(product._id as string)}
className="text-red-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-950/20"
className="h-8 w-8 text-muted-foreground hover:text-destructive hover:bg-destructive/10"
title="Delete Product"
>
<Trash className="h-4 w-4" />
</Button>
</div>
</TableCell>
</TableRow>
</motion.tr>
);
const renderTableHeader = () => (
<TableHeader className="bg-gray-50 dark:bg-zinc-800/50">
<TableRow className="hover:bg-transparent">
<TableHeader className="bg-muted/50 sticky top-0 z-10">
<TableRow className="hover:bg-transparent border-border/50">
<TableHead className="w-[200px]">Product</TableHead>
<TableHead className="hidden sm:table-cell text-center">
Category
@@ -166,57 +191,86 @@ const ProductTable = ({
<TableHead className="hidden lg:table-cell text-center">
Enabled
</TableHead>
<TableHead className="text-right">Actions</TableHead>
<TableHead className="text-right pr-6">Actions</TableHead>
</TableRow>
</TableHeader>
);
return (
<div className="space-y-6">
<div className="space-y-8">
{/* Enabled Products Table */}
<div className="rounded-lg border dark:border-zinc-700 shadow-sm overflow-hidden">
<Table className="relative">
<Card className="border-border/40 bg-background/50 backdrop-blur-sm shadow-sm overflow-hidden">
<CardHeader className="py-4 px-6 border-b border-border/50 bg-muted/30">
<CardTitle className="text-lg font-medium flex items-center gap-2">
<CheckCircle className="h-5 w-5 text-primary" />
Active Products
<Badge variant="secondary" className="ml-2 bg-background/80 backdrop-blur-sm">
{sortedEnabledProducts.length}
</Badge>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<div className="max-h-[600px] overflow-auto">
<Table>
{renderTableHeader()}
<TableBody>
<AnimatePresence mode="popLayout">
{loading ? (
Array.from({ length: 1 }).map((_, index) => (
<TableRow key={index}>
<TableCell>Loading...</TableCell>
<TableCell>Loading...</TableCell>
<TableCell>Loading...</TableCell>
<TableCell>Loading...</TableCell>
<TableCell>Loading...</TableCell>
<TableCell>Loading...</TableCell>
<TableRow>
<TableCell colSpan={6} className="h-32 text-center text-muted-foreground">
Loading products...
</TableCell>
</TableRow>
))
) : sortedEnabledProducts.length > 0 ? (
sortedEnabledProducts.map((product) => renderProductRow(product))
sortedEnabledProducts.map((product, index) => renderProductRow(product, index))
) : (
<TableRow>
<TableCell colSpan={6} className="h-24 text-center">
No enabled products found.
<TableCell colSpan={6} className="h-32 text-center text-muted-foreground">
<div className="flex flex-col items-center justify-center gap-2">
<PackageOffset className="h-8 w-8 opacity-50" />
<p>No active products found</p>
</div>
</TableCell>
</TableRow>
)}
</AnimatePresence>
</TableBody>
</Table>
</div>
</CardContent>
</Card>
{/* Disabled Products Section */}
{!loading && disabledProducts.length > 0 && (
<div className="rounded-lg border dark:border-zinc-700 shadow-sm overflow-hidden bg-gray-50/30 dark:bg-zinc-900/30">
<Table className="relative">
<Card className="border-border/40 bg-background/30 backdrop-blur-sm shadow-sm overflow-hidden opacity-90">
<CardHeader className="py-4 px-6 border-b border-border/50 bg-muted/20">
<CardTitle className="text-lg font-medium flex items-center gap-2 text-muted-foreground">
<Archive className="h-5 w-5" />
Archived / Disabled
<Badge variant="outline" className="ml-2">
{sortedDisabledProducts.length}
</Badge>
</CardTitle>
</CardHeader>
<CardContent className="p-0">
<div className="max-h-[400px] overflow-auto">
<Table>
{renderTableHeader()}
<TableBody>
{sortedDisabledProducts.map((product) =>
renderProductRow(product, true),
<AnimatePresence mode="popLayout">
{sortedDisabledProducts.map((product, index) =>
renderProductRow(product, index, true),
)}
</AnimatePresence>
</TableBody>
</Table>
</div>
</CardContent>
</Card>
)}
</div>
);
};
export default ProductTable;