import { useEffect, useState } from "react"; import { supabase } from "@/integrations/supabase/client"; import { AppLayout } from "@/components/AppLayout"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Badge } from "@/components/ui/badge"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Skeleton } from "@/components/ui/skeleton"; import { toast } from "@/hooks/use-toast"; import { Star, Check, X, Edit, Trash2 } from "lucide-react"; interface Review { id: string; user_id: string; product_id: string | null; type: string; rating: number; title: string; body: string; is_approved: boolean; created_at: string; profiles: { full_name: string | null; email: string | null } | null; products: { title: string } | null; } export default function AdminReviews() { const [reviews, setReviews] = useState([]); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState({ type: "all", status: "all" }); const [editReview, setEditReview] = useState(null); const [editForm, setEditForm] = useState({ title: "", body: "" }); useEffect(() => { fetchReviews(); }, []); const fetchReviews = async () => { setLoading(true); const { data, error } = await supabase .from("reviews") .select(` *, profiles (full_name, email), products (title) `) .order("created_at", { ascending: false }); if (error) { console.error("Fetch reviews error:", error); toast({ title: "Error", description: "Gagal mengambil data ulasan", variant: "destructive" }); setReviews([]); } else { setReviews((data as unknown as Review[]) || []); } setLoading(false); }; const handleApprove = async (id: string, approved: boolean) => { const { error } = await supabase .from("reviews") .update({ is_approved: approved }) .eq("id", id); if (error) { toast({ title: "Error", description: "Gagal mengubah status", variant: "destructive" }); } else { toast({ title: "Berhasil", description: approved ? "Ulasan disetujui" : "Ulasan ditolak" }); fetchReviews(); } }; const handleDelete = async (id: string) => { if (!confirm("Hapus ulasan ini?")) return; const { error } = await supabase.from("reviews").delete().eq("id", id); if (error) { toast({ title: "Error", description: "Gagal menghapus", variant: "destructive" }); } else { toast({ title: "Berhasil", description: "Ulasan dihapus" }); fetchReviews(); } }; const handleEdit = (review: Review) => { setEditReview(review); setEditForm({ title: review.title, body: review.body }); }; const handleSaveEdit = async () => { if (!editReview) return; const { error } = await supabase .from("reviews") .update({ title: editForm.title, body: editForm.body }) .eq("id", editReview.id); if (error) { toast({ title: "Error", description: "Gagal menyimpan", variant: "destructive" }); } else { toast({ title: "Berhasil", description: "Ulasan diperbarui" }); setEditReview(null); fetchReviews(); } }; const filteredReviews = reviews.filter((r) => { if (filter.type !== "all" && r.type !== filter.type) return false; if (filter.status === "approved" && !r.is_approved) return false; if (filter.status === "pending" && r.is_approved) return false; return true; }); const pendingReviews = reviews.filter((r) => !r.is_approved); const renderStars = (rating: number) => (
{[1, 2, 3, 4, 5].map((i) => ( ))}
); const getTypeLabel = (type: string) => { switch (type) { case "consulting": return "Konsultasi"; case "bootcamp": return "Bootcamp"; case "webinar": return "Webinar"; case "general": return "Umum"; default: return type; } }; if (loading) { return (
{[...Array(3)].map((_, i) => ( ))}
); } return (

Ulasan

Kelola ulasan dari member

Daftar ({filteredReviews.length}) Menunggu ({pendingReviews.length})
{filteredReviews.length === 0 ? (

Belum ada ulasan

Ulasan dari member akan muncul di sini setelah mereka mengirimkan ulasan.

) : ( filteredReviews.map((review) => (
{renderStars(review.rating)} {getTypeLabel(review.type)} {review.is_approved ? "Disetujui" : "Menunggu"}

{review.title}

{review.body &&

{review.body}

}
{review.profiles?.full_name || review.profiles?.email || "Unknown"} {review.products && • {review.products.title}} • {new Date(review.created_at).toLocaleDateString("id-ID")}
{!review.is_approved && ( )} {review.is_approved && ( )}
)) )}
{pendingReviews.length === 0 ? (

Semua ulasan sudah dimoderasi

Tidak ada ulasan yang menunggu persetujuan.

) : ( pendingReviews.map((review) => (
{renderStars(review.rating)} {getTypeLabel(review.type)}

{review.title}

{review.body &&

{review.body}

}
{review.profiles?.full_name || review.profiles?.email} {review.products && • {review.products.title}}
)) )}
setEditReview(null)}> Edit Ulasan
setEditForm({ ...editForm, title: e.target.value })} className="border-2" />