// VendorsTable.tsx 'use client' import { ColumnDef } from '@tanstack/react-table' import { DataTable } from './DataTable' import { Button } from '../ui/button' import DialogWrapper from '../dialogs/DialogWrapper' import CreateVendorForm from '../forms/CreateVendorForm' import { useState } from 'react' import { fetchVendorsClient } from '@/lib/helper/fetchVendors' import { Vendor, VendorType, VendorStatus } from '@prisma/client' import { Badge } from '../ui/badge' import { useRouter } from 'next/navigation' interface VendorRow { id: string slug: string name: string type: VendorType description?: string | null website?: string | null contactPerson?: string | null email?: string | null phone?: string | null status: VendorStatus isBooked: boolean bookedDate?: Date | null quotedPrice?: number | null finalCost?: number | null depositPaid?: number | null depositDueDate?: Date | null finalPaymentDue?: Date | null createdAt: Date } interface Props { initialVendors: VendorRow[] } // Format vendor type for display const formatVendorType = (type: VendorType): string => { return type.charAt(0) + type.slice(1).toLowerCase() } // Format vendor status with colors const formatVendorStatus = (status: VendorStatus): { label: string, color: string } => { const colors: Record = { RESEARCHING: 'bg-gray-100 text-gray-800', CONTACTING: 'bg-blue-100 text-blue-800', RESPONDED: 'bg-yellow-100 text-yellow-800', PROPOSAL_RECEIVED: 'bg-purple-100 text-purple-800', NEGOTIATING: 'bg-orange-100 text-orange-800', CONTRACT_SENT: 'bg-indigo-100 text-indigo-800', CONTRACT_SIGNED: 'bg-green-100 text-green-800', DECLINED: 'bg-red-100 text-red-800', BACKUP: 'bg-slate-100 text-slate-800', } const label = status.charAt(0) + status.slice(1).toLowerCase().replace('_', ' ') return { label, color: colors[status] } } // Format currency const formatCurrency = (amount?: number | null): string => { if (!amount) return '—' return new Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', }).format(amount) } // Format date const formatDate = (date?: Date | null): string => { if (!date) return '—' return new Date(date).toLocaleDateString() } const columns: ColumnDef[] = [ { accessorKey: 'name', header: 'Name', cell: ({ row }) => (
{row.original.name}
{row.original.contactPerson && (
{row.original.contactPerson}
)}
), }, { accessorKey: 'type', header: 'Type', cell: ({ row }) => ( {formatVendorType(row.original.type)} ), }, { accessorKey: 'contact', header: 'Contact', cell: ({ row }) => (
{row.original.email && (
{row.original.email}
)} {row.original.phone && (
{row.original.phone}
)}
), }, { accessorKey: 'status', header: 'Status', cell: ({ row }) => { const status = formatVendorStatus(row.original.status) return ( {status.label} ) }, }, { accessorKey: 'isBooked', header: 'Booked', cell: ({ row }) => ( {row.original.isBooked ? 'Booked' : 'Not Booked'} ), }, { accessorKey: 'cost', header: 'Cost', cell: ({ row }) => (
{row.original.finalCost ? (
{formatCurrency(row.original.finalCost)}
) : row.original.quotedPrice ? (
{formatCurrency(row.original.quotedPrice)}
) : (
)}
), }, { accessorKey: 'deposit', header: 'Deposit', cell: ({ row }) => (
{row.original.depositPaid ? (
{formatCurrency(row.original.depositPaid)}
) : (
)} {row.original.depositDueDate && (
Due: {formatDate(row.original.depositDueDate)}
)}
), }, { accessorKey: 'createdAt', header: 'Added', cell: ({ row }) => formatDate(row.original.createdAt), }, ] export default function VendorsTable({ initialVendors }: Props) { const [isDialogOpen, setIsDialogOpen] = useState(false) const [vendors, setVendors] = useState(initialVendors) const router = useRouter() async function refreshVendors() { try { const updated = await fetchVendorsClient() setVendors(updated) } catch (err) { console.error('Failed to refresh vendors:', err) } } // Handle row click const handleRowClick = (vendor: VendorRow) => { router.push(`/vendors/${vendor.slug}`) } return (

Vendors

Manage your wedding vendors and suppliers

{ await refreshVendors() setIsDialogOpen(false) }} /> } />
) }