TKK_E32231405/app/dashboard/manajemen-posyandu/review/[id]/AdminReviewList.tsx

115 lines
5.7 KiB
TypeScript

'use client'
import { useState } from 'react'
import { Star, Trash2, Calendar, User, MessageCircle } from 'lucide-react'
import { deleteReview } from './action-admin-review'
import { showSwal } from '@/lib/swal'
interface Review {
id: string
rating: number
ulasan: string
nama_pengulas: string
created_at: string
}
interface Props {
posyanduId: string
initialReviews: Review[]
}
export function AdminReviewList({ posyanduId, initialReviews }: Props) {
const [isDeleting, setIsDeleting] = useState<string | null>(null)
const handleDelete = async (reviewId: string) => {
const result = await showSwal.confirm(
'Hapus Ulasan?',
'Apakah Anda yakin ingin menghapus ulasan ini? Tindakan ini tidak dapat dibatalkan.'
)
if (!result.isConfirmed) return
setIsDeleting(reviewId)
try {
const res = await deleteReview(reviewId, posyanduId)
if (res.success) {
showSwal.success('Berhasil!', 'Ulasan telah dihapus.')
} else {
showSwal.error('Gagal!', res.error || 'Gagal menghapus ulasan.')
}
} catch (err) {
showSwal.error('Gagal!', 'Terjadi kesalahan sistem.')
} finally {
setIsDeleting(null)
}
}
return (
<div className="bg-white rounded-3xl border-2 border-black shadow-[8px_8px_0px_0px_rgba(0,0,0,1)] overflow-hidden">
<div className="p-6 border-b-2 border-black bg-purple-600 flex items-center justify-between">
<h3 className="text-lg font-black text-white flex items-center gap-3 uppercase">
<MessageCircle className="w-6 h-6" />
Ulasan Masyarakat
</h3>
<span className="bg-white text-purple-600 px-3 py-1 rounded-full text-xs font-black border-2 border-black">
{initialReviews.length} TOTAL
</span>
</div>
<div className="divide-y divide-gray-100">
{initialReviews.length > 0 ? (
initialReviews.map((rev) => (
<div key={rev.id} className="p-8 hover:bg-gray-50/50 transition-all flex flex-col gap-4">
<div className="flex justify-between items-start">
<div className="flex items-center gap-4">
<div className="w-12 h-12 bg-purple-100 text-purple-600 rounded-2xl flex items-center justify-center font-black text-xl border-2 border-purple-200">
{rev.nama_pengulas?.[0] || 'A'}
</div>
<div>
<p className="font-bold text-gray-900 text-lg">{rev.nama_pengulas || 'Orang Tua'}</p>
<div className="flex items-center gap-3 mt-1">
<div className="flex gap-0.5">
{[...Array(5)].map((_, i) => (
<Star
key={i}
className={`w-3.5 h-3.5 ${i < rev.rating ? 'text-yellow-400 fill-current' : 'text-gray-200'}`}
/>
))}
</div>
<div className="w-1 h-1 bg-gray-300 rounded-full"></div>
<div className="flex items-center gap-1.5 text-[10px] text-gray-400 font-bold uppercase tracking-widest">
<Calendar className="w-3 h-3" />
{new Date(rev.created_at).toLocaleDateString('id-ID', { day: 'numeric', month: 'long', year: 'numeric' })}
</div>
</div>
</div>
</div>
<button
onClick={() => handleDelete(rev.id)}
disabled={isDeleting === rev.id}
className="p-3 text-gray-400 hover:text-red-600 hover:bg-red-50 rounded-xl transition-all border border-transparent hover:border-red-100 disabled:opacity-50"
title="Hapus Ulasan"
>
<Trash2 className={`w-5 h-5 ${isDeleting === rev.id ? 'animate-pulse' : ''}`} />
</button>
</div>
<div className="bg-gray-50 rounded-2xl p-5 border-2 border-gray-100 relative">
<p className="text-gray-700 font-semibold italic leading-relaxed text-sm">
"{rev.ulasan}"
</p>
</div>
</div>
))
) : (
<div className="p-20 text-center flex flex-col items-center gap-4 text-gray-300">
<MessageCircle className="w-16 h-16 opacity-10" />
<div className="flex flex-col gap-1">
<p className="font-black text-xl">Belum Ada Ulasan</p>
<p className="text-sm font-semibold opacity-60">Posyandu ini belum memiliki riwayat ulasan dari masyarakat.</p>
</div>
</div>
)}
</div>
</div>
)
}