import { ConfirmDialog } from '@/components/confirm-dialog'; import { DataTable } from '@/components/data-table'; import { ImagePreviewModal } from '@/components/image-preview-modal'; import { Button } from '@/components/ui/button'; import { Combobox, ComboboxContent, ComboboxEmpty, ComboboxInput, ComboboxItem, ComboboxList } from '@/components/ui/combobox'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table'; import { destroy, create as productCreate, index as productIndex, edit as productEdit, toggleStatus } from '@/routes/admin/master/products'; import { Head, router } from '@inertiajs/react'; import type { Row } from '@tanstack/react-table'; import { Filter, Plus, X } from 'lucide-react'; import { useMemo, useState } from 'react'; import type { Product } from './columns'; import { createProductColumns } from './columns'; type Props = { products: Product[]; filters: { status?: string; name?: string; }; }; function formatCurrency(amount: number): string { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, }).format(amount); } function formatNumber(num: number): string { return new Intl.NumberFormat('id-ID').format(num); } function VariantPhotoPreview({ url, title }: { url: string; title: string }) { const [open, setOpen] = useState(false); return ( <> ); } function VariantSubRow({ row, searchValue }: { row: Row; searchValue?: string }) { const allVariants = row.original.product_variants ?? []; const query = (searchValue ?? '').toLowerCase().trim(); const variants = query ? allVariants.filter((v) => v.name.toLowerCase().includes(query)) : allVariants; return ( Foto Nama Varian Stok Bagus Stok Reject Stok Ecer Harga {variants.length === 0 ? ( Tidak ada varian. ) : ( variants.map((variant) => ( {variant.photo_url ? ( ) : (
N/A
)}
{variant.name} {formatNumber(variant.stock)} {formatNumber(variant.reject_stock)} {formatNumber(variant.retail_stock)} {variant.product_prices?.length > 0 ? (
{variant.product_prices.map((p) => ( {p.type_label}:{' '} {formatCurrency(p.price)} ))}
) : '-'}
)) )}
); } export default function ProductIndex({ products, filters }: Props) { const [deleting, setDeleting] = useState(null); const [filterOpen, setFilterOpen] = useState(false); const hasActiveFilters = filters.status || filters.name; const productNames = useMemo(() => { const names = products.map((p) => p.name); return [...new Set(names)].sort(); }, [products]); function applyFilter(key: string, value: string) { const newFilters = { ...filters }; if (value === '' || value === 'all') { delete newFilters[key as keyof typeof newFilters]; } else { newFilters[key as keyof typeof newFilters] = value; } router.get(productIndex(), newFilters, { preserveState: true, replace: true, }); } function clearFilters() { router.get(productIndex(), {}, { preserveState: true, replace: true, }); setFilterOpen(false); } function handleDelete() { if (!deleting) { return; } router.delete(destroy.url(deleting.id), { onSuccess: () => setDeleting(null), }); } const columns = createProductColumns({ handleEdit: (product) => { window.location.href = productEdit.url(product.id); }, handleDeleteClick: (product) => setDeleting(product), toggleStatusUrl: (id) => toggleStatus.url(id), }); const filterToolbar = (
Filter {hasActiveFilters && ( )}
applyFilter('name', value as string)} > Tidak ada produk ditemukan. {productNames.map((name) => ( {name} ))}
); return ( <>

Produk

} defaultExpanded toolbar={filterToolbar} /> { if (!open) { setDeleting(null); } }} title="Hapus Produk" description={`Apakah Anda yakin ingin menghapus produk "${deleting?.name}"? Tindakan ini tidak dapat dibatalkan.`} confirmLabel="Hapus" onConfirm={handleDelete} />
); } ProductIndex.layout = { breadcrumbs: [ { title: 'Master', href: productIndex.url(), }, { title: 'Produk', href: productIndex.url(), }, ], };