import { useState, useEffect, useCallback } from 'react'; import toast from 'react-hot-toast'; import { AxiosError } from 'axios'; import { getGoogleReviewsApi, createGoogleReviewApi, updateGoogleReviewApi, deleteGoogleReviewApi, GoogleReview, } from '@/api/googleReview'; import GoogleReviewModal from '@/components/GoogleReviewModal/GoogleReviewModal'; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { Switch } from '@/components/ui/switch'; import { Input } from '@/components/ui/input'; import { Loader2, RefreshCw, Plus, Pencil, Trash2, ExternalLink, Star } from 'lucide-react'; export default function GoogleReviewPage() { const [reviews, setReviews] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(''); const [reviewModal, setReviewModal] = useState(false); const [editingReview, setEditingReview] = useState(null); const [searchText, setSearchText] = useState(''); const [reviewForm, setReviewForm] = useState>({ reviewerName: '', reviewerImage: '', rating: 5, review: '', reviewDate: null, googleReviewUrl: '', isFeatured: false, isActive: true, sortOrder: 1000, }); const fetchData = useCallback(async () => { setLoading(true); setError(''); try { const res = await getGoogleReviewsApi(); setReviews(res.data || []); } catch (err) { if (err instanceof AxiosError) { setError(err.response?.data?.message || 'Failed to sync Google review records.'); } else { setError('An unhandled database communication error occurred.'); } } finally { setLoading(false); } }, []); useEffect(() => { fetchData(); }, [fetchData]); const handleToggleStatus = async (review: GoogleReview) => { if (review.id === undefined) return; try { await updateGoogleReviewApi(review.id, { isActive: !review.isActive }); toast.success(`Review status updated successfully`); fetchData(); } catch (err) { console.error(err); } }; const handleToggleFeatured = async (review: GoogleReview) => { if (review.id === undefined) return; try { await updateGoogleReviewApi(review.id, { isFeatured: !review.isFeatured }); toast.success(`Review featured status updated`); fetchData(); } catch (err) { console.error(err); } }; const handleDeleteReview = async (id: number) => { const confirmDelete = window.confirm( 'Are you completely sure you want to remove this testimonial record? This step is irreversible.' ); if (!confirmDelete) return; try { await deleteGoogleReviewApi(id); fetchData(); } catch (err) { console.error(err); } }; const openAddReview = () => { setEditingReview(null); setReviewForm({ reviewerName: '', reviewerImage: '', rating: 5, review: '', reviewDate: null, googleReviewUrl: '', isFeatured: false, isActive: true, sortOrder: 1000, }); setReviewModal(true); }; const openEditReview = (review: GoogleReview) => { setEditingReview(review); setReviewForm({ ...review }); setReviewModal(true); }; const saveReview = async () => { if (!reviewForm.reviewerName) return toast.error('Reviewer name is required.'); if (!reviewForm.review) return toast.error('Review message content is required.'); try { const finalData = { ...reviewForm }; if (editingReview?.id) { const changedFields: Record = {}; Object.keys(finalData).forEach((key) => { const k = key as keyof GoogleReview; if (JSON.stringify(finalData[k]) !== JSON.stringify(editingReview[k])) { changedFields[k] = finalData[k]; } }); delete changedFields.id; if (Object.keys(changedFields).length === 0) { setReviewModal(false); return; } await updateGoogleReviewApi(editingReview.id, changedFields); } else { await createGoogleReviewApi(finalData as GoogleReview); } setReviewModal(false); fetchData(); } catch (err) { console.error(err); } }; const filteredReviews = reviews.filter((r) => r.reviewerName.toLowerCase().includes(searchText.toLowerCase())); return (

Google Reviews

setSearchText(e.target.value)} className="w-[260px] text-base" />
{error &&
{error}
} Testimonials Sequence Directory
Order Avatar Reviewer Rating Testimonial Source Link Featured Status Actions {loading ? ( ) : filteredReviews.length === 0 ? ( No reviews found matching your criteria. ) : ( filteredReviews.map((review) => ( {review.sortOrder} {review.reviewerImage ? ( {review.reviewerName} ) : (
{review.reviewerName.charAt(0).toUpperCase()}
)}
{review.reviewerName}
{review.reviewDate && (
{new Date(review.reviewDate).toLocaleDateString()}
)}
{review.rating}
"{review.review}"
{review.googleReviewUrl ? ( Link ) : ( - )} handleToggleFeatured(review)} />
handleToggleStatus(review)} /> {review.isActive ? 'Active' : 'Disabled'}
)) )}
); }