Files
ember-market-frontend/components/tables/product-table.tsx
NotII be746664c5 Add profit analysis modal and cost tracking for products
Introduces a Profit Analysis modal for products, allowing users to view profit, margin, and markup calculations based on cost per unit and pricing tiers. Adds cost per unit input to the product modal, updates product types, and integrates the analysis modal into the products page and product table. This enhances product management with profit tracking and analysis features.
2025-08-26 20:52:38 +01:00

137 lines
5.5 KiB
TypeScript

import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Edit, Trash, AlertTriangle, CheckCircle, AlertCircle, Calculator } 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";
interface ProductTableProps {
products: Product[];
loading: boolean;
onEdit: (product: Product) => void;
onDelete: (productId: string) => void;
onToggleEnabled: (productId: string, enabled: boolean) => void;
onProfitAnalysis?: (productId: string, productName: string) => void;
getCategoryNameById: (categoryId: string) => string;
}
const ProductTable = ({
products,
loading,
onEdit,
onDelete,
onToggleEnabled,
onProfitAnalysis,
getCategoryNameById
}: ProductTableProps) => {
const sortedProducts = [...products].sort((a, b) => {
const categoryNameA = getCategoryNameById(a.category);
const categoryNameB = getCategoryNameById(b.category);
return categoryNameA.localeCompare(categoryNameB);
});
const getStockIcon = (product: Product) => {
if (!product.stockTracking) return null;
if (product.stockStatus === 'out_of_stock') {
return <AlertTriangle className="h-4 w-4 text-red-500" />;
} else if (product.stockStatus === 'low_stock') {
return <AlertCircle className="h-4 w-4 text-amber-500" />;
} else {
return <CheckCircle className="h-4 w-4 text-green-500" />;
}
};
return (
<div className="rounded-lg border dark:border-zinc-700 shadow-sm overflow-hidden">
<Table className="relative">
<TableHeader className="bg-gray-50 dark:bg-zinc-800/50">
<TableRow className="hover:bg-transparent">
<TableHead className="w-[200px]">Product</TableHead>
<TableHead className="text-center">Category</TableHead>
<TableHead className="text-center">Unit</TableHead>
<TableHead className="text-center">Stock</TableHead>
<TableHead className="text-center">Enabled</TableHead>
<TableHead className="text-right">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{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>
))
) : sortedProducts.length > 0 ? (
sortedProducts.map((product) => (
<TableRow key={product._id} className="transition-colors hover:bg-gray-50 dark:hover:bg-zinc-800/70">
<TableCell>
<div className="font-medium truncate max-w-[180px]">{product.name}</div>
</TableCell>
<TableCell className="text-center">{getCategoryNameById(product.category)}</TableCell>
<TableCell className="text-center">{product.unitType}</TableCell>
<TableCell className="text-center">
{product.stockTracking ? (
<div className="flex items-center justify-center gap-1">
{getStockIcon(product)}
<span className="text-sm">
{product.currentStock !== undefined ? product.currentStock : 0} {product.unitType}
</span>
</div>
) : (
<Badge variant="outline" className="text-xs">Not Tracked</Badge>
)}
</TableCell>
<TableCell className="text-center">
<Switch
checked={product.enabled !== false}
onCheckedChange={(checked) => onToggleEnabled(product._id as string, checked)}
/>
</TableCell>
<TableCell className="text-right flex justify-end space-x-1">
{onProfitAnalysis && (
<Button
variant="ghost"
size="sm"
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"
title="Profit Analysis"
>
<Calculator className="h-4 w-4" />
</Button>
)}
<Button variant="ghost" size="sm" onClick={() => onEdit(product)}>
<Edit className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="sm"
onClick={() => onDelete(product._id as string)}
className="text-red-500 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-950/20"
>
<Trash className="h-4 w-4" />
</Button>
</TableCell>
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={6} className="h-24 text-center">
No products found.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
);
};
export default ProductTable;