import React, { useState, useRef, useEffect } from 'react'; import { MessageSquare, Send, User, Loader2 } from 'lucide-react'; import { useTranslation } from 'react-i18next'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { feedbackService } from '../../services/feedback.service'; import { toast } from 'react-toastify'; import { format } from 'date-fns'; import { Button, Input } from '../common'; import type { PhotoFeedback } from '../../services/feedback.service'; interface PhotoCommentsProps { photoId: string; gallerySlug: string; comments: PhotoFeedback[]; isEnabled: boolean; requireNameEmail: boolean; showToGuests: boolean; onCommentAdded?: () => void; } export const PhotoComments: React.FC = ({ photoId, gallerySlug, comments, isEnabled, requireNameEmail, showToGuests, onCommentAdded }) => { const { t } = useTranslation(); const queryClient = useQueryClient(); const [showCommentForm, setShowCommentForm] = useState(false); const [commentText, setCommentText] = useState(''); const [guestName, setGuestName] = useState(''); const [guestEmail, setGuestEmail] = useState(''); const [errors, setErrors] = useState>({}); const textareaRef = useRef(null); // Auto-resize textarea useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = 'auto'; textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`; } }, [commentText]); const submitCommentMutation = useMutation({ mutationFn: (data: any) => feedbackService.submitFeedback(gallerySlug, photoId, { feedback_type: 'comment', comment_text: data.comment_text, guest_name: data.guest_name, guest_email: data.guest_email }), onSuccess: (response) => { setCommentText(''); setShowCommentForm(false); queryClient.invalidateQueries({ queryKey: ['photo-feedback', gallerySlug, photoId] }); if (response.message) { toast.info(response.message); } else { toast.success(t('feedback.commentSubmitted', 'Comment submitted')); } if (onCommentAdded) { onCommentAdded(); } }, onError: (error: any) => { if (error.response?.status === 429) { toast.error(t('feedback.rateLimited', 'Please wait before commenting again')); } else if (error.response?.data?.errors) { setErrors(error.response.data.errors); } else { toast.error(t('feedback.commentError', 'Failed to submit comment')); } } }); const handleSubmitComment = (e: React.FormEvent) => { e.preventDefault(); setErrors({}); // Validate const newErrors: Record = {}; if (!commentText.trim()) { newErrors.comment_text = t('feedback.commentRequired', 'Comment is required'); } if (requireNameEmail) { if (!guestName.trim()) { newErrors.guest_name = t('feedback.nameRequired', 'Name is required'); } if (!guestEmail.trim()) { newErrors.guest_email = t('feedback.emailRequired', 'Email is required'); } } if (Object.keys(newErrors).length > 0) { setErrors(newErrors); return; } submitCommentMutation.mutate({ comment_text: commentText.trim(), guest_name: guestName.trim(), guest_email: guestEmail.trim() }); }; if (!isEnabled) return null; // Filter comments based on visibility settings const visibleComments = showToGuests ? comments.filter(c => c.is_approved && !c.is_hidden) : comments.filter(c => c.is_mine); return (
{/* Comments Header */}

{t('feedback.comments', 'Comments')} {visibleComments.length > 0 && ( ({visibleComments.length}) )}

{!showCommentForm && ( )}
{/* Comment Form */} {showCommentForm && (
{requireNameEmail && (
setGuestName(e.target.value)} error={errors.guest_name} size="sm" /> setGuestEmail(e.target.value)} error={errors.guest_email} size="sm" />
)}