import 'package:flutter/material.dart'; import '../models/comment_models.dart'; import '../services/post_service.dart'; class CommentsWidget extends StatefulWidget { final String postId; final int commentCount; const CommentsWidget({ Key? key, required this.postId, required this.commentCount, }) : super(key: key); @override _CommentsWidgetState createState() => _CommentsWidgetState(); } class _CommentsWidgetState extends State { List comments = []; bool isLoading = true; String? errorMessage; final TextEditingController _commentController = TextEditingController(); bool _isCreatingComment = false; Comment? _replyingTo; @override void initState() { super.initState(); _loadComments(); } @override void dispose() { _commentController.dispose(); super.dispose(); } Future _loadComments() async { setState(() { isLoading = true; errorMessage = null; }); final result = await PostService.getComments(widget.postId); setState(() { isLoading = false; if (result['success'] == true) { comments = result['comments'] as List; } else { errorMessage = result['message'] ?? 'Failed to load comments'; comments = []; } }); } void _setReplyingTo(Comment? comment) { setState(() { _replyingTo = comment; if (comment == null) { _commentController.clear(); } }); } Future _createComment() async { final body = _commentController.text.trim(); if (body.isEmpty || _isCreatingComment) return; setState(() { _isCreatingComment = true; }); try { final result = await PostService.createComment( postId: widget.postId, body: body, replyComment: _replyingTo?.id, ); if (result['success'] == true) { _commentController.clear(); _setReplyingTo(null); await _loadComments(); // Reload comments to show the new one } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(result['message'] ?? 'Failed to create comment'), backgroundColor: Colors.red, ), ); } } catch (e) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('Network error occurred'), backgroundColor: Colors.red, ), ); } finally { setState(() { _isCreatingComment = false; }); } } String _formatTimeAgo(DateTime dateTime) { final now = DateTime.now(); final difference = now.difference(dateTime); if (difference.inDays > 0) { return '${difference.inDays}d ago'; } else if (difference.inHours > 0) { return '${difference.inHours}h ago'; } else if (difference.inMinutes > 0) { return '${difference.inMinutes}m ago'; } else { return 'Just now'; } } Widget _buildComment(Comment comment, {double leftPadding = 0}) { final safePadding = leftPadding < 0 ? 0.0 : leftPadding; return Container( margin: EdgeInsets.only(left: safePadding, bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Avatar CircleAvatar( radius: 16, backgroundColor: Color(0xFF6A4C93), child: Text( comment.creator.displayName.isNotEmpty ? comment.creator.displayName[0].toUpperCase() : 'U', style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), SizedBox(width: 8), // Comment content Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header with name and time Row( children: [ Text( comment.creator.displayName, style: TextStyle( fontWeight: FontWeight.w600, fontSize: 14, color: Colors.black87, ), ), SizedBox(width: 8), Text( _formatTimeAgo(comment.creationDate), style: TextStyle( fontSize: 12, color: Colors.grey[600], ), ), ], ), SizedBox(height: 4), // Reply indicator if this is a reply if (comment.replyUser != null) ...[ Container( padding: EdgeInsets.symmetric( horizontal: 8, vertical: 2, ), decoration: BoxDecoration( color: Colors.grey[100], borderRadius: BorderRadius.circular(12), ), child: Text( 'Replying to ${comment.replyUser!.displayName}', style: TextStyle( fontSize: 11, color: Colors.grey[600], fontStyle: FontStyle.italic, ), ), ), SizedBox(height: 6), ], // Comment body Text( comment.body, style: TextStyle( fontSize: 14, color: Colors.black87, height: 1.3, ), ), SizedBox(height: 8), // Reply button InkWell( onTap: () => _setReplyingTo(comment), child: Text( 'Reply', style: TextStyle( fontSize: 12, color: Color(0xFF6A4C93), fontWeight: FontWeight.w500, ), ), ), ], ), ), ], ), // Replies if (comment.replies.isNotEmpty) ...[ SizedBox(height: 12), ...comment.replies.map( (reply) => _buildComment(reply, leftPadding: safePadding + 24), ), ], ], ), ); } Widget _buildErrorState() { return Container( padding: EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.error_outline, size: 64, color: Colors.grey[400]), SizedBox(height: 16), Text( 'Failed to load comments', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.grey[700], ), ), SizedBox(height: 8), Text( errorMessage ?? 'Unknown error occurred', textAlign: TextAlign.center, style: TextStyle(fontSize: 14, color: Colors.grey[600]), ), SizedBox(height: 16), ElevatedButton.icon( onPressed: _loadComments, icon: Icon(Icons.refresh), label: Text('Retry'), style: ElevatedButton.styleFrom( backgroundColor: Color(0xFF6A4C93), foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), ), ], ), ); } Widget _buildEmptyState() { return Container( padding: EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.chat_bubble_outline, size: 64, color: Colors.grey[400]), SizedBox(height: 16), Text( 'No comments yet', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.grey[700], ), ), SizedBox(height: 8), Text( 'Be the first to share your thoughts!', style: TextStyle(fontSize: 14, color: Colors.grey[600]), ), ], ), ); } @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), child: Column( children: [ // Header Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( border: Border(bottom: BorderSide(color: Colors.grey[200]!)), ), child: Row( children: [ Text( 'Comments', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w600, color: Colors.black87, ), ), if (widget.commentCount > 0) ...[ SizedBox(width: 8), Container( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: Color(0xFF6A4C93).withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Text( '${widget.commentCount}', style: TextStyle( fontSize: 12, color: Color(0xFF6A4C93), fontWeight: FontWeight.w600, ), ), ), ], Spacer(), if (isLoading) SizedBox( width: 16, height: 16, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( Color(0xFF6A4C93), ), ), ), ], ), ), // Content Expanded( child: isLoading ? Center( child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation( Color(0xFF6A4C93), ), ), ) : errorMessage != null ? _buildErrorState() : comments.isEmpty ? _buildEmptyState() : ListView.builder( padding: EdgeInsets.only(left: 16, right: 16, top: 16), itemCount: comments.length, itemBuilder: (context, index) => _buildComment(comments[index]), ), ), // Comment input section Container( decoration: BoxDecoration( color: Colors.white, border: Border(top: BorderSide(color: Colors.grey[200]!)), ), padding: EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Reply indicator if (_replyingTo != null) ...[ Container( padding: EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: Color(0xFF6A4C93).withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Icon(Icons.reply, size: 16, color: Color(0xFF6A4C93)), SizedBox(width: 8), Expanded( child: Text( 'Replying to ${_replyingTo!.creator.displayName}', style: TextStyle( fontSize: 12, color: Color(0xFF6A4C93), fontWeight: FontWeight.w500, ), ), ), IconButton( onPressed: () => _setReplyingTo(null), icon: Icon( Icons.close, size: 16, color: Color(0xFF6A4C93), ), constraints: BoxConstraints( minWidth: 24, minHeight: 24, ), padding: EdgeInsets.zero, ), ], ), ), SizedBox(height: 12), ], // Comment input Row( children: [ CircleAvatar( radius: 16, backgroundColor: Color(0xFF6A4C93), child: Text( 'U', // TODO: Use actual user initial style: TextStyle( color: Colors.white, fontSize: 12, fontWeight: FontWeight.bold, ), ), ), SizedBox(width: 12), Expanded( child: Container( decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(20), border: Border.all(color: Colors.grey[300]!), ), child: Row( children: [ Expanded( child: TextField( controller: _commentController, decoration: InputDecoration( hintText: _replyingTo != null ? 'Reply to ${_replyingTo!.creator.displayName}...' : 'Write a comment...', border: InputBorder.none, contentPadding: EdgeInsets.symmetric( horizontal: 16, vertical: 10, ), hintStyle: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), maxLines: null, textCapitalization: TextCapitalization.sentences, ), ), if (_isCreatingComment) Container( margin: EdgeInsets.only(right: 8), width: 24, height: 24, child: CircularProgressIndicator( strokeWidth: 2, valueColor: AlwaysStoppedAnimation( Color(0xFF6A4C93), ), ), ) else IconButton( onPressed: _createComment, icon: Icon( Icons.send, color: Color(0xFF6A4C93), size: 20, ), constraints: BoxConstraints( minWidth: 36, minHeight: 36, ), ), ], ), ), ), ], ), ], ), ), ], ), ); } }