import { InfiniteScroll } from '@inertiajs/react'; import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, } from 'lucide-react'; import * as React from 'react'; import type { PaginationState } from '@/components/data-table'; import { useDebounce } from '@/components/data-table'; import { Button } from '@/components/ui/button'; import { Card, CardContent } from '@/components/ui/card'; import { Input } from '@/components/ui/input'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; export type { PaginationState } from '@/components/data-table'; interface DataCardsProps { data: TData[]; renderCard: (item: TData, index: number) => React.ReactNode; getRowId?: (item: TData) => string | number; searchKey?: string; searchPlaceholder?: string; emptyText?: string; toolbar?: React.ReactNode; pagination: PaginationState; onPageChange?: (page: number) => void; onPerPageChange?: (perPage: number) => void; onSearchChange?: (search: string) => void; searchValue?: string; /** * Enables infinite scroll instead of page-based pagination. `propName` * must match the Inertia page prop returned via `Inertia::scroll()` on * the backend so the frontend can track its merge/scroll metadata. */ infiniteScroll?: { propName: string; buffer?: number; }; } export function DataCards({ data, renderCard, getRowId, searchKey, searchPlaceholder = 'Ketikkan sesuatu...', emptyText = 'Tidak ada data.', toolbar, pagination, onPageChange, onPerPageChange, onSearchChange, searchValue, infiniteScroll, }: DataCardsProps) { const isInfiniteScroll = !!infiniteScroll; const [localSearch, setLocalSearch] = React.useState(searchValue ?? ''); const [previousSearchValue, setPreviousSearchValue] = React.useState(searchValue); if (searchValue !== previousSearchValue) { setPreviousSearchValue(searchValue); setLocalSearch(searchValue ?? ''); } const handleSearchDebounced = useDebounce( (value: string) => onSearchChange?.(value), 300, ); function handleSearchChange(value: string) { setLocalSearch(value); handleSearchDebounced(value); } const currentPage = pagination.current_page; const totalPages = pagination.last_page; return ( <> {(searchKey || toolbar || onPerPageChange) && (
{searchKey && ( handleSearchChange(event.target.value) } className="max-w-sm" /> )} {toolbar}
{onPerPageChange && ( )}
)} {data.length ? ( isInfiniteScroll ? ( loading ? (

Memuat data...

) : hasMore ? null : (

Semua data telah ditampilkan.

) } > {data.map((item, index) => ( {renderCard(item, index)} ))}
) : (
{data.map((item, index) => ( {renderCard(item, index)} ))}
) ) : ( {emptyText} )} {isInfiniteScroll ? (

Menampilkan {data.length.toLocaleString('id-ID')} dari{' '} {pagination.total.toLocaleString('id-ID')} data

) : (
{`Halaman ${currentPage} dari ${totalPages}`}
)} ); }