import { useState, useEffect, useCallback } from 'react' import { commentsApi, usersApi, Comment, UserSearchResult } from '../services/collaboration' import { useAuth } from '../contexts/AuthContext' interface CommentsProps { taskId: string } export function Comments({ taskId }: CommentsProps) { const { user } = useAuth() const [comments, setComments] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [newComment, setNewComment] = useState('') const [submitting, setSubmitting] = useState(false) const [replyTo, setReplyTo] = useState(null) const [editingId, setEditingId] = useState(null) const [editContent, setEditContent] = useState('') const [mentionSuggestions, setMentionSuggestions] = useState([]) const [showMentions, setShowMentions] = useState(false) const fetchComments = useCallback(async () => { try { setLoading(true) const response = await commentsApi.list(taskId) setComments(response.comments) setError(null) } catch (err) { setError('Failed to load comments') } finally { setLoading(false) } }, [taskId]) useEffect(() => { fetchComments() }, [fetchComments]) const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!newComment.trim() || submitting) return try { setSubmitting(true) const comment = await commentsApi.create(taskId, newComment, replyTo || undefined) if (replyTo) { // For replies, we'd need to refresh or update the parent await fetchComments() } else { setComments(prev => [...prev, comment]) } setNewComment('') setReplyTo(null) } catch (err) { setError('Failed to post comment') } finally { setSubmitting(false) } } const handleEdit = async (commentId: string) => { if (!editContent.trim()) return try { const updated = await commentsApi.update(commentId, editContent) setComments(prev => prev.map(c => (c.id === commentId ? updated : c))) setEditingId(null) setEditContent('') } catch (err) { setError('Failed to update comment') } } const handleDelete = async (commentId: string) => { if (!confirm('Delete this comment?')) return try { await commentsApi.delete(commentId) await fetchComments() } catch (err) { setError('Failed to delete comment') } } const handleMentionSearch = async (query: string) => { if (query.length < 1) { setMentionSuggestions([]) setShowMentions(false) return } try { const results = await usersApi.search(query) setMentionSuggestions(results) setShowMentions(results.length > 0) } catch { setMentionSuggestions([]) } } const handleInputChange = (value: string) => { setNewComment(value) // Check for @mention const atMatch = value.match(/@(\w*)$/) if (atMatch) { handleMentionSearch(atMatch[1]) } else { setShowMentions(false) } } const insertMention = (userResult: UserSearchResult) => { const newValue = newComment.replace(/@\w*$/, `@${userResult.name} `) setNewComment(newValue) setShowMentions(false) } if (loading) return
Loading comments...
return (

Comments ({comments.length})

{error && (
{error}
)} {/* Comment list */}
{comments.map(comment => (
{comment.author.name} {new Date(comment.created_at).toLocaleString()} {comment.is_edited && ( (edited) )}
{user?.id === comment.author.id && !comment.is_deleted && (
)}
{editingId === comment.id ? (