71 lines
2.3 KiB
TypeScript
71 lines
2.3 KiB
TypeScript
'use client'
|
|
|
|
import { useState, useMemo } from 'react'
|
|
import { Search, Building2 } from 'lucide-react'
|
|
import PosyanduCard from './PosyanduCard'
|
|
|
|
interface Posyandu {
|
|
id: string
|
|
nama_posyandu: string
|
|
alamat: string
|
|
kontak: string | null
|
|
latitude: number | null
|
|
longitude: number | null
|
|
link_google_maps: string | null
|
|
petugas?: {
|
|
nama_petugas: string
|
|
nomor_hp: string | null
|
|
jabatan: string | null
|
|
}[]
|
|
reviews?: {
|
|
rating: number
|
|
ulasan: string
|
|
nama_pengulas: string
|
|
}[]
|
|
}
|
|
|
|
interface Props {
|
|
initialData: Posyandu[]
|
|
}
|
|
|
|
export default function PosyanduList({ initialData }: Props) {
|
|
const [searchTerm, setSearchTerm] = useState('')
|
|
|
|
const filteredData = useMemo(() => {
|
|
return initialData.filter(p =>
|
|
p.nama_posyandu.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
p.alamat.toLowerCase().includes(searchTerm.toLowerCase())
|
|
)
|
|
}, [initialData, searchTerm])
|
|
|
|
return (
|
|
<div className="flex flex-col gap-6">
|
|
{/* Search Bar */}
|
|
<div className="relative w-full md:w-96">
|
|
<Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-400" />
|
|
<input
|
|
type="text"
|
|
placeholder="Cari nama posyandu atau alamat..."
|
|
value={searchTerm}
|
|
onChange={(e) => setSearchTerm(e.target.value)}
|
|
className="w-full pl-10 pr-4 py-2.5 bg-gray-50 border-2 border-gray-100 focus:border-black rounded-xl text-sm font-semibold outline-none transition-all"
|
|
/>
|
|
</div>
|
|
|
|
{/* Grid of Cards */}
|
|
{filteredData.length === 0 ? (
|
|
<div className="py-20 text-center flex flex-col items-center gap-2 text-gray-400">
|
|
<Building2 className="w-12 h-12 opacity-20" />
|
|
<p className="font-bold">Tidak ada posyandu ditemukan</p>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
{filteredData.map((p) => (
|
|
<PosyanduCard key={p.id} data={p} />
|
|
))}
|
|
</div>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|