import React, { useState, useEffect, useRef, useCallback } from 'react'; import { useApp } from '../../context/AppContext'; import { showBackButton, currentUser, hapticNotification, hapticImpact } from '../../services/auth'; import { api } from '../../services/api'; import CommentItem from './CommentItem'; import './CommentsPanel.css'; export default function CommentsPanel() { const { isCommentsOpen, setIsCommentsOpen, currentCard, showToast, getUserProfile, handleApiResponse, syncCardComments, addCommentToCard, } = useApp(); const [comments, setComments] = useState([]); const [authors, setAuthors] = useState({}); const [isLoading, setIsLoading] = useState(false); const [newComment, setNewComment] = useState(''); const [isSending, setIsSending] = useState(false); const listRef = useRef(null); // Telegram BackButton useEffect(() => { if (isCommentsOpen) { const cleanup = showBackButton(() => { hapticImpact('light'); setIsCommentsOpen(false); }); return cleanup; } }, [isCommentsOpen, setIsCommentsOpen]); const cardId = currentCard?.card_id; const loadComments = useCallback(async () => { if (!cardId) return; setIsLoading(true); try { const result = await api.getComments(cardId); handleApiResponse(result); if (!result.error && Array.isArray(result.result)) { const loadedComments = result.result; setComments(loadedComments); syncCardComments(cardId, loadedComments.map((c) => c.comment_id)); // Fetch author profiles for all unique authors const uniqueAuthorIds = Array.from(new Set(loadedComments.map((c) => c.author_id))); const authorsData = {}; await Promise.all( uniqueAuthorIds.map(async (authorId) => { const profile = await getUserProfile(authorId); if (profile) { authorsData[authorId] = profile; } }) ); setAuthors(authorsData); } else { setComments([]); } } catch (err) { console.error('Load comments error:', err); } finally { setIsLoading(false); } }, [cardId, getUserProfile, handleApiResponse, syncCardComments]); // Load comments only when panel opens or active card ID changes useEffect(() => { if (isCommentsOpen && cardId) { loadComments(); } }, [isCommentsOpen, cardId, loadComments]); async function handleSend() { const text = newComment.trim(); if (!text || isSending || !currentCard) return; setIsSending(true); hapticImpact('light'); try { const result = await api.addComment(currentUser.id, currentCard.card_id, text); handleApiResponse(result); if (!result.error && result.result) { setNewComment(''); showToast('Комментарий опубликован'); hapticNotification('success'); const createdComment = result.result; setComments((prev) => [...prev, createdComment]); addCommentToCard(currentCard.card_id, createdComment.comment_id); // Add current user to authors map setAuthors((prev) => ({ ...prev, [currentUser.id]: currentUser, })); // Scroll to bottom setTimeout(() => { if (listRef.current) { listRef.current.scrollTop = listRef.current.scrollHeight; } }, 100); } else { showToast(typeof result.result === 'string' ? result.result : 'Ошибка отправки комментария'); hapticNotification('error'); } } catch (err) { console.error('Send comment error:', err); showToast('Ошибка отправки'); hapticNotification('error'); } finally { setIsSending(false); } } function handleKeyDown(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); handleSend(); } } const handleClose = () => { hapticImpact('light'); setIsCommentsOpen(false); }; return (
Загрузка комментариев...
Комментариев пока нет
Будь первым, кто поделится мнением!