Files
roboco/panel/src/components/products/product-table.tsx
T

159 lines
5.1 KiB
TypeScript
Raw Normal View History

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";
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 (
<>
<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) => (
<ResponsiveTableCard key={product.id}>
<div className="flex items-start justify-between gap-2">
<div className="min-w-0">
<Button
2026-06-03 06:35:03 +02:00
onClick={() => setEditingProductId(product.id)}
variant="link"
className="h-auto p-0 font-medium text-foreground"
2026-06-03 06:35:03 +02:00
>
{product.name}
</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>
<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
))}
</ResponsiveTableCardList>
}
/>
2026-06-03 06:35:03 +02:00
{/* Edit Product Dialog */}
{editingProductId && (
<EditProductDialog
productId={editingProductId}
open={!!editingProductId}
onOpenChange={(open) => {
if (!open) setEditingProductId(null);
}}
/>
)}
</>
);
}