import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:real_estate_mobile/core/constants/app_colors.dart'; import 'package:real_estate_mobile/features/profile/presentation/providers/profile_provider.dart'; class TestimonialsTab extends ConsumerStatefulWidget { const TestimonialsTab({super.key}); @override ConsumerState createState() => _TestimonialsTabState(); } class _TestimonialsTabState extends ConsumerState { List> _testimonials = []; bool _isLoadingTestimonials = false; String _testimonialSort = 'latest'; String? _testimonialLink; bool _isGeneratingLink = false; bool _linkCopied = false; @override void initState() { super.initState(); _loadTestimonials(); } Future _loadTestimonials() async { if (_isLoadingTestimonials) return; setState(() => _isLoadingTestimonials = true); try { final repo = ref.read(profileRepositoryProvider); final data = await repo.getMyTestimonials(sort: _testimonialSort); setState(() { _testimonials = data; _isLoadingTestimonials = false; }); } catch (_) { setState(() => _isLoadingTestimonials = false); } } Future _generateTestimonialLink() async { setState(() => _isGeneratingLink = true); try { final repo = ref.read(profileRepositoryProvider); final token = await repo.generateTestimonialLink(); setState(() { _testimonialLink = 'https://re-quest.co/testimonials/$token'; _isGeneratingLink = false; }); } catch (e) { setState(() => _isGeneratingLink = false); if (mounted) _showSnackBar('Failed to generate link: $e', isError: true); } } @override Widget build(BuildContext context) { return ListView( padding: const EdgeInsets.fromLTRB(24, 10, 24, 30), children: [ const Center( child: Text( 'Add Testimonials', style: TextStyle( fontFamily: 'Fractul', fontSize: 25, fontWeight: FontWeight.w700, color: AppColors.primaryDark, ), ), ), const SizedBox(height: 10), const Center( child: Text( 'What people are saying about you', textAlign: TextAlign.center, style: TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.primaryDark, ), ), ), const SizedBox(height: 20), const Center( child: Text( 'Create Testimonials', style: TextStyle( fontFamily: 'Fractul', fontSize: 25, fontWeight: FontWeight.w700, color: AppColors.primaryDark, ), ), ), const SizedBox(height: 16), SizedBox( width: double.infinity, height: 43, child: ElevatedButton( onPressed: _isGeneratingLink ? null : _generateTestimonialLink, style: ElevatedButton.styleFrom( backgroundColor: AppColors.accentOrange, padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15)), ), child: _isGeneratingLink ? const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white)) : const Text('Generate Link', style: TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white)), ), ), const SizedBox(height: 16), if (_testimonialLink != null) Container( height: 43, decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), border: Border.all( color: AppColors.primaryDark.withValues(alpha: 0.1), ), ), child: Row( children: [ Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 12), child: Text( _testimonialLink!, overflow: TextOverflow.ellipsis, style: const TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w300, color: Colors.black, ), ), ), ), Container( width: 1, height: 43, color: AppColors.primaryDark.withValues(alpha: 0.1), ), GestureDetector( onTap: () { Clipboard.setData( ClipboardData(text: _testimonialLink!)); setState(() => _linkCopied = true); Future.delayed(const Duration(seconds: 2), () { if (mounted) setState(() => _linkCopied = false); }); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10), child: Row( children: [ Icon( _linkCopied ? Icons.check : Icons.copy_outlined, size: 18, color: Colors.black, ), const SizedBox(width: 4), Text( _linkCopied ? 'Copied!' : 'Copy', style: const TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, color: Colors.black, ), ), ], ), ), ), ], ), ), const SizedBox(height: 30), Row( children: [ const Text( 'Reviews', style: TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black, ), ), const Spacer(), GestureDetector( onTap: () { setState(() { _testimonialSort = _testimonialSort == 'latest' ? 'oldest' : 'latest'; }); _loadTestimonials(); }, child: Row( children: [ Text( 'Sort By : ${_testimonialSort == 'latest' ? 'Latest' : 'Oldest'}', style: const TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black, ), ), const SizedBox(width: 4), const Icon(Icons.arrow_downward, size: 14, color: Colors.black), ], ), ), ], ), const SizedBox(height: 16), if (_isLoadingTestimonials) const Center( child: Padding( padding: EdgeInsets.all(40), child: CircularProgressIndicator(color: AppColors.accentOrange), )) else if (_testimonials.isEmpty) Container( padding: const EdgeInsets.symmetric(vertical: 40, horizontal: 16), decoration: BoxDecoration( color: const Color(0xFFD9D9D9).withValues(alpha: 0.25), borderRadius: BorderRadius.circular(7), ), child: Center( child: Column( children: [ Icon(Icons.rate_review_outlined, size: 48, color: AppColors.primaryDark.withValues(alpha: 0.3)), const SizedBox(height: 12), const Text( 'No testimonials yet', style: TextStyle( fontFamily: 'Fractul', fontSize: 16, fontWeight: FontWeight.w600, color: AppColors.primaryDark, ), ), const SizedBox(height: 6), Text( 'Share your testimonial link with clients to start collecting reviews.', textAlign: TextAlign.center, style: TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, color: AppColors.primaryDark.withValues(alpha: 0.6), ), ), ], ), ), ) else Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFFD9D9D9).withValues(alpha: 0.25), borderRadius: BorderRadius.circular(7), ), child: Column( children: _testimonials .map((t) => _buildTestimonialCard(t)) .toList(), ), ), ], ); } Widget _buildTestimonialCard(Map testimonial) { final rating = (testimonial['rating'] as num?)?.toInt() ?? 5; final text = testimonial['text'] as String? ?? ''; final authorName = testimonial['authorName'] as String? ?? ''; final authorRole = testimonial['authorRole'] as String? ?? ''; final createdAt = testimonial['createdAt'] as String?; return Container( margin: const EdgeInsets.only(bottom: 12), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(7), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: List.generate( 5, (i) => Icon( i < rating ? Icons.star : Icons.star_border, size: 16, color: i < rating ? AppColors.accentOrange : AppColors.primaryDark.withValues(alpha: 0.3), ), ), ), const SizedBox(height: 10), Text( text, style: const TextStyle( fontFamily: 'SourceSerif4', fontSize: 14, color: Colors.black, height: 1.5, ), ), const SizedBox(height: 12), RichText( text: TextSpan( children: [ TextSpan( text: authorName, style: const TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w700, color: AppColors.primaryDark, ), ), if (authorRole.isNotEmpty || createdAt != null) TextSpan( text: ' , ${authorRole.isNotEmpty ? authorRole : ''}${createdAt != null ? ' ยท ${_formatRelativeTime(createdAt)}' : ''}', style: const TextStyle( fontFamily: 'Fractul', fontSize: 14, fontWeight: FontWeight.w300, color: AppColors.primaryDark, ), ), ], ), ), ], ), ); } String _formatRelativeTime(String dateStr) { try { final date = DateTime.parse(dateStr); final now = DateTime.now(); final diff = now.difference(date); if (diff.inDays == 0) return 'Today'; if (diff.inDays == 1) return 'Yesterday'; if (diff.inDays < 30) return '${diff.inDays} days ago'; if (diff.inDays < 365) return '${diff.inDays ~/ 30} months ago'; return DateFormat('MMM d, y').format(date); } catch (_) { return ''; } } void _showSnackBar(String message, {bool isError = false}) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: isError ? Colors.red : const Color(0xFF638559), ), ); } }