2026-06-03 06:35:03 +02:00
|
|
|
"use client";
|
|
|
|
|
|
|
|
|
|
import { useState } from "react";
|
|
|
|
|
import { Badge } from "@/components/ui/badge";
|
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
|
|
|
import {
|
|
|
|
|
Table,
|
|
|
|
|
TableBody,
|
|
|
|
|
TableCell,
|
|
|
|
|
TableHead,
|
|
|
|
|
TableHeader,
|
|
|
|
|
TableRow,
|
|
|
|
|
} from "@/components/ui/table";
|
2026-07-03 19:24:00 +02:00
|
|
|
import {
|
|
|
|
|
ResponsiveTable,
|
|
|
|
|
ResponsiveTableCardList,
|
|
|
|
|
ResponsiveTableCard,
|
|
|
|
|
ResponsiveTableCardRow,
|
|
|
|
|
} from "@/components/ui/responsive-table";
|
2026-06-03 06:35:03 +02:00
|
|
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
|
|
|
import { Boxes, Pencil } from "lucide-react";
|
|
|
|
|
import type { ProductSummary } from "@/types";
|
|
|
|
|
import { EditProductDialog } from "./edit-product-dialog";
|
|
|
|
|
|
|
|
|
|
interface ProductTableProps {
|
|
|
|
|
products: ProductSummary[] | undefined;
|
|
|
|
|
isLoading: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function ProductTable({ products, isLoading }: ProductTableProps) {
|
|
|
|
|
const [editingProductId, setEditingProductId] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="space-y-3">
|
|
|
|
|
{Array.from({ length: 5 }).map((_, i) => (
|
|
|
|
|
<Skeleton key={i} className="h-14 w-full" />
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!products || products.length === 0) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="text-center py-12 text-muted-foreground">
|
|
|
|
|
<Boxes className="h-12 w-12 mx-auto mb-4 opacity-50" />
|
|
|
|
|
<p className="text-lg font-medium">No products found</p>
|
|
|
|
|
<p className="text-sm">Create a product to map cells to projects</p>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<>
|
2026-07-03 19:24:00 +02:00
|
|
|
<ResponsiveTable
|
|
|
|
|
table={
|
|
|
|
|
<div className="border rounded-lg">
|
|
|
|
|
<Table>
|
|
|
|
|
<TableHeader>
|
|
|
|
|
<TableRow>
|
|
|
|
|
<TableHead>Product</TableHead>
|
|
|
|
|
<TableHead>Cells Mapped</TableHead>
|
|
|
|
|
<TableHead className="w-[100px]">Actions</TableHead>
|
|
|
|
|
</TableRow>
|
|
|
|
|
</TableHeader>
|
|
|
|
|
<TableBody>
|
|
|
|
|
{products.map((product) => (
|
|
|
|
|
<TableRow key={product.id}>
|
|
|
|
|
<TableCell>
|
|
|
|
|
<div>
|
|
|
|
|
<Button
|
|
|
|
|
onClick={() => setEditingProductId(product.id)}
|
|
|
|
|
variant="link"
|
|
|
|
|
className="h-auto p-0 font-medium text-foreground"
|
|
|
|
|
>
|
|
|
|
|
{product.name}
|
|
|
|
|
</Button>
|
|
|
|
|
<p className="text-xs text-muted-foreground font-mono">
|
|
|
|
|
{product.slug}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell>
|
|
|
|
|
<Badge className="bg-blue-500/10 text-blue-500">
|
|
|
|
|
{product.cell_count} / 3
|
|
|
|
|
</Badge>
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell>
|
|
|
|
|
<div className="flex items-center gap-1">
|
|
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
onClick={() => setEditingProductId(product.id)}
|
|
|
|
|
title="Edit product"
|
|
|
|
|
>
|
|
|
|
|
<Pencil className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</TableCell>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))}
|
|
|
|
|
</TableBody>
|
|
|
|
|
</Table>
|
|
|
|
|
</div>
|
|
|
|
|
}
|
|
|
|
|
cards={
|
|
|
|
|
<ResponsiveTableCardList>
|
2026-06-03 06:35:03 +02:00
|
|
|
{products.map((product) => (
|
2026-07-03 19:24:00 +02:00
|
|
|
<ResponsiveTableCard key={product.id}>
|
|
|
|
|
<div className="flex items-start justify-between gap-2">
|
|
|
|
|
<div className="min-w-0">
|
2026-06-17 06:36:28 +02:00
|
|
|
<Button
|
2026-06-03 06:35:03 +02:00
|
|
|
onClick={() => setEditingProductId(product.id)}
|
2026-06-17 06:36:28 +02:00
|
|
|
variant="link"
|
|
|
|
|
className="h-auto p-0 font-medium text-foreground"
|
2026-06-03 06:35:03 +02:00
|
|
|
>
|
|
|
|
|
{product.name}
|
2026-06-17 06:36:28 +02:00
|
|
|
</Button>
|
2026-06-29 05:38:21 +02:00
|
|
|
<p className="text-xs text-muted-foreground font-mono">
|
|
|
|
|
{product.slug}
|
|
|
|
|
</p>
|
2026-06-03 06:35:03 +02:00
|
|
|
</div>
|
2026-07-03 19:24:00 +02:00
|
|
|
<Button
|
|
|
|
|
variant="ghost"
|
|
|
|
|
size="icon"
|
|
|
|
|
className="shrink-0"
|
|
|
|
|
onClick={() => setEditingProductId(product.id)}
|
|
|
|
|
title="Edit product"
|
|
|
|
|
>
|
|
|
|
|
<Pencil className="h-4 w-4" />
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="mt-3 divide-y">
|
|
|
|
|
<ResponsiveTableCardRow label="Cells Mapped">
|
|
|
|
|
<Badge className="bg-blue-500/10 text-blue-500">
|
|
|
|
|
{product.cell_count} / 3
|
|
|
|
|
</Badge>
|
|
|
|
|
</ResponsiveTableCardRow>
|
|
|
|
|
</div>
|
|
|
|
|
</ResponsiveTableCard>
|
2026-06-03 06:35:03 +02:00
|
|
|
))}
|
2026-07-03 19:24:00 +02:00
|
|
|
</ResponsiveTableCardList>
|
|
|
|
|
}
|
|
|
|
|
/>
|
2026-06-03 06:35:03 +02:00
|
|
|
|
|
|
|
|
{/* Edit Product Dialog */}
|
|
|
|
|
{editingProductId && (
|
|
|
|
|
<EditProductDialog
|
|
|
|
|
productId={editingProductId}
|
|
|
|
|
open={!!editingProductId}
|
|
|
|
|
onOpenChange={(open) => {
|
|
|
|
|
if (!open) setEditingProductId(null);
|
|
|
|
|
}}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|