import { useState } from 'react'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { getComments, createComment, type CommentListResponse, } from '../../services/commentService'; import { useUser } from '@/features/auth/hooks/useUser'; import { useToast } from '@/hooks/useToast'; import { useIsRateLimited } from '@/hooks/useIsRateLimited'; import { Card, CardContent } from '@/components/ui/card'; import { ErrorDisplay } from '@/components/ui/ErrorDisplay'; import type { TrackComment } from '../../services/commentService'; import { CommentSectionHeader } from './CommentSectionHeader'; import { CommentSectionSkeleton } from './CommentSectionSkeleton'; import { CommentSectionEmpty } from './CommentSectionEmpty'; import { CommentSectionError } from './CommentSectionError'; import { CommentEditor } from './CommentEditor'; import { CommentList } from './CommentList'; import { CommentSectionPagination } from './CommentSectionPagination'; export interface CommentSectionProps { trackId: string; } const LIMIT = 20; export function CommentSection({ trackId }: CommentSectionProps) { const { data: user } = useUser(); const toast = useToast(); const queryClient = useQueryClient(); const isRateLimited = useIsRateLimited(); const [newComment, setNewComment] = useState(''); const [mutationError, setMutationError] = useState(null); const [page, setPage] = useState(1); const [lastCommentContent, setLastCommentContent] = useState(''); const [retryCount, setRetryCount] = useState(0); const { data: commentsData, isLoading, error, } = useQuery({ queryKey: ['trackComments', trackId, page], queryFn: () => getComments(trackId, page, LIMIT), enabled: !!trackId, }); const createCommentMutation = useMutation({ mutationFn: (content: string) => createComment(trackId, content), onMutate: async (content: string) => { await queryClient.cancelQueries({ queryKey: ['trackComments', trackId] }); const previousComments = queryClient.getQueryData([ 'trackComments', trackId, page, ]); if (previousComments && user) { const optimisticComment: TrackComment = { id: `temp-${Date.now()}`, track_id: trackId, user_id: user.id, content: content.trim(), is_edited: false, created_at: new Date().toISOString(), updated_at: new Date().toISOString(), user: { id: user.id, username: user.username || '', avatar: user.avatar_url, }, }; queryClient.setQueryData( ['trackComments', trackId, page], { ...previousComments, comments: [optimisticComment, ...previousComments.comments], total: (previousComments.total || 0) + 1, }, ); } return { previousComments }; }, onError: (err: Error, _content, context) => { if (context?.previousComments) { queryClient.setQueryData( ['trackComments', trackId, page], context.previousComments, ); } setMutationError( new Error(err.message || 'Erreur lors de la publication'), ); setLastCommentContent(newComment.trim()); }, onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['trackComments', trackId] }); setNewComment(''); setMutationError(null); setRetryCount(0); setLastCommentContent(''); toast.success('Commentaire publiƩ'); }, }); const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); if (!newComment.trim() || !user) return; setLastCommentContent(newComment.trim()); createCommentMutation.mutate(newComment.trim()); }; const handleRetry = async () => { if (!lastCommentContent || retryCount >= 3) return; setRetryCount((prev) => prev + 1); try { await createCommentMutation.mutateAsync(lastCommentContent); } catch { // Handled by mutation onError } }; const topLevelComments = commentsData?.comments?.filter((c: TrackComment) => !c.parent_id) || []; const total = commentsData?.total || 0; const totalPages = Math.ceil(total / LIMIT); return ( {mutationError && ( { setMutationError(null); setRetryCount(0); setLastCommentContent(''); }} /> )} {isLoading ? ( ) : error ? ( queryClient.invalidateQueries({ queryKey: ['trackComments', trackId], }) } /> ) : topLevelComments.length === 0 ? ( ) : ( <> )} ); }