'use client'; import { useCallback } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import { Download } from 'lucide-react'; import { useForm } from 'react-hook-form'; import { formatDate } from '@kit/shared/dates'; import { Badge } from '@kit/ui/badge'; import { Button } from '@kit/ui/button'; import { Input } from '@kit/ui/input'; import { useFileDownloadAction } from '@kit/ui/use-file-download-action'; import { STATUS_LABELS, getMemberStatusColor } from '../lib/member-utils'; import { exportMembers, exportMembersExcel, } from '../server/actions/member-actions'; interface MembersDataTableProps { data: Array>; total: number; page: number; pageSize: number; account: string; accountId: string; duesCategories: Array<{ id: string; name: string }>; } const STATUS_OPTIONS = [ { value: '', label: 'Alle' }, { value: 'active', label: 'Aktiv' }, { value: 'inactive', label: 'Inaktiv' }, { value: 'pending', label: 'Ausstehend' }, { value: 'resigned', label: 'Ausgetreten' }, ] as const; export function MembersDataTable({ data, total, page, pageSize, account, accountId, duesCategories, }: MembersDataTableProps) { const router = useRouter(); const searchParams = useSearchParams(); const currentSearch = searchParams.get('search') ?? ''; const currentStatus = searchParams.get('status') ?? ''; const totalPages = Math.max(1, Math.ceil(total / pageSize)); const form = useForm({ defaultValues: { search: currentSearch, }, }); const updateParams = useCallback( (updates: Record) => { const params = new URLSearchParams(searchParams.toString()); for (const [key, value] of Object.entries(updates)) { if (value) { params.set(key, value); } else { params.delete(key); } } // Reset to page 1 on filter change if (!('page' in updates)) { params.delete('page'); } router.push(`?${params.toString()}`); }, [router, searchParams], ); const handleSearch = useCallback( (e: React.FormEvent) => { e.preventDefault(); const search = form.getValues('search'); updateParams({ search }); }, [form, updateParams], ); const handleStatusChange = useCallback( (e: React.ChangeEvent) => { updateParams({ status: e.target.value }); }, [updateParams], ); const handlePageChange = useCallback( (newPage: number) => { updateParams({ page: String(newPage) }); }, [updateParams], ); const handleRowClick = useCallback( (memberId: string) => { router.push(`/home/${account}/members-cms/${memberId}`); }, [router, account], ); const { execute: execCsvExport, isPending: isCsvExporting } = useFileDownloadAction(exportMembers, { successMessage: 'CSV-Export heruntergeladen', errorMessage: 'CSV-Export fehlgeschlagen', }); const { execute: execExcelExport, isPending: isExcelExporting } = useFileDownloadAction(exportMembersExcel, { successMessage: 'Excel-Export heruntergeladen', errorMessage: 'Excel-Export fehlgeschlagen', }); const isExporting = isCsvExporting || isExcelExporting; return (
{/* Toolbar */}
{/* Table */}
{data.length === 0 ? ( ) : ( data.map((member) => { const memberId = String(member.id ?? ''); const status = String(member.status ?? 'active'); return ( handleRowClick(memberId)} className="hover:bg-muted/50 cursor-pointer border-b transition-colors" > ); }) )}
Nr Name E-Mail Ort Status Eintritt
Keine Mitglieder gefunden.
{String(member.member_number ?? '—')} {String(member.last_name ?? '')},{' '} {String(member.first_name ?? '')} {String(member.email ?? '—')} {String(member.city ?? '—')} {STATUS_LABELS[status] ?? status} {formatDate(member.entry_date as string)}
{/* Pagination */}

{total} Mitglied{total !== 1 ? 'er' : ''} insgesamt

Seite {page} von {totalPages}
); }