'use client' import { useState, useEffect, useCallback } from 'react' 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 { Table, TableBody, TableCell, TableHead, TableHeader, TableRow, } from '@/components/ui/table' import { Star, Search, Check, X, Eye, Trash2 } from 'lucide-react' import { toast } from 'sonner' import { formatDistanceToNow } from 'date-fns' interface Review { id: string rating: number title?: string comment?: string isVerified: boolean isApproved: boolean helpfulVotes: number reportCount: number createdAt: string user: { name: string email: string } product: { name: string } } export default function AdminReviewsPage() { const [reviews, setReviews] = useState([]) const [loading, setLoading] = useState(true) const [search, setSearch] = useState('') const [statusFilter, setStatusFilter] = useState<'all' | 'pending' | 'approved'>('all') const fetchReviews = useCallback(async () => { try { setLoading(true) const params = new URLSearchParams({ page: '1', limit: '50', admin: 'true' }) if (search) params.append('search', search) if (statusFilter !== 'all') { params.append('approved', statusFilter === 'approved' ? 'true' : 'false') } const response = await fetch(`/api/admin/reviews?${params}`) const data = await response.json() if (response.ok) { setReviews(data.reviews || []) } else { toast.error('Failed to load reviews') } } catch (error) { toast.error('Failed to load reviews') } finally { setLoading(false) } }, [search, statusFilter]) useEffect(() => { fetchReviews() }, [fetchReviews]) const handleApprove = async (reviewId: string) => { try { const response = await fetch(`/api/admin/reviews/${reviewId}/approve`, { method: 'POST' }) if (response.ok) { toast.success('Review approved') setReviews(prev => prev.map(review => review.id === reviewId ? { ...review, isApproved: true } : review ) ) } else { toast.error('Failed to approve review') } } catch (error) { toast.error('Failed to approve review') } } const handleReject = async (reviewId: string) => { try { const response = await fetch(`/api/admin/reviews/${reviewId}/reject`, { method: 'POST' }) if (response.ok) { toast.success('Review rejected') setReviews(prev => prev.map(review => review.id === reviewId ? { ...review, isApproved: false } : review ) ) } else { toast.error('Failed to reject review') } } catch (error) { toast.error('Failed to reject review') } } const handleDelete = async (reviewId: string) => { if (!confirm('Are you sure you want to delete this review?')) return try { const response = await fetch(`/api/admin/reviews/${reviewId}`, { method: 'DELETE' }) if (response.ok) { toast.success('Review deleted') setReviews(prev => prev.filter(review => review.id !== reviewId)) } else { toast.error('Failed to delete review') } } catch (error) { toast.error('Failed to delete review') } } const renderStars = (rating: number) => { return Array.from({ length: 5 }, (_, index) => ( )) } return (

Reviews Management

Moderate customer reviews and feedback

All Reviews
setSearch(e.target.value)} className="pl-10 w-64" />
{loading ? (
Loading...
) : ( Product Customer Rating Review Status Stats Date Actions {reviews.map((review) => (

{review.product.name}

{review.user.name}

{review.user.email}

{renderStars(review.rating)} ({review.rating})
{review.title && (

{review.title}

)} {review.comment && (

{review.comment}

)}
{review.isApproved ? 'Approved' : 'Pending'} {review.isVerified && ( Verified )}
👍 {review.helpfulVotes}
{review.reportCount > 0 && (
🚩 {review.reportCount}
)}
{formatDistanceToNow(new Date(review.createdAt), { addSuffix: true })}
{!review.isApproved && ( )} {review.isApproved && ( )}
))}
)}
) }