import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:intl/intl.dart'; import 'package:proxibuy/core/config/app_colors.dart'; import 'package:proxibuy/data/models/notification_model.dart'; import 'package:proxibuy/presentation/offer/bloc/offer_bloc.dart'; import 'package:proxibuy/presentation/offer/bloc/offer_state.dart'; import 'package:proxibuy/presentation/pages/product_detail_page.dart'; class NotificationPanel extends StatefulWidget { final VoidCallback onClose; final VoidCallback? onListChanged; const NotificationPanel({super.key, required this.onClose, this.onListChanged}); @override State createState() => _NotificationPanelState(); } class _NotificationPanelState extends State { List _notifications = []; bool _isLoading = true; String _errorMessage = ''; final Dio _dio = Dio(); final FlutterSecureStorage _storage = const FlutterSecureStorage(); @override void initState() { super.initState(); _fetchNotifications(); } Future _fetchNotifications() async { final token = await _storage.read(key: 'accessToken'); if (token == null) { if (mounted) { setState(() { _isLoading = false; _errorMessage = 'برای مشاهده اعلان‌ها، لطفا ابتدا وارد شوید.'; }); widget.onListChanged?.call(); } return; } try { final response = await _dio.get( 'https://proxybuy.liara.run/notify/get', options: Options(headers: {'Authorization': 'Bearer $token'}), ); if (response.statusCode == 200 && mounted) { final List data = response.data['data'] ?? []; setState(() { _notifications = data.map((json) => NotificationModel.fromJson(json)).toList(); _isLoading = false; }); widget.onListChanged?.call(); } else if (response.statusCode == 201) { if (mounted) { setState(() { _isLoading = false; _errorMessage = 'اعلانی وجود ندارد'; }); widget.onListChanged?.call(); } } } catch (e) { if (mounted) { setState(() { _isLoading = false; _errorMessage = 'اتصال به سرور برقرار نشد.'; }); widget.onListChanged?.call(); } } } Future _ignoreNotification(String notificationId) async { final token = await _storage.read(key: 'accessToken'); if (token == null) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('خطا: شما وارد حساب کاربری نشده‌اید.')), ); return; } try { final response = await _dio.get( 'https://proxybuy.liara.run/notify/ignore/$notificationId', options: Options(headers: {'Authorization': 'Bearer $token'}), ); if (response.statusCode == 200 && mounted) { setState(() { _notifications.removeWhere((n) => n.id == notificationId); }); widget.onListChanged?.call(); } else { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text(response.data?['message'] ?? 'خطا در حذف اعلان.')), ); } } } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('خطا در ارتباط با سرور.')), ); debugPrint('Error ignoring notification: $e'); } } } String _formatTimeAgo(DateTime dateTime) { final now = DateTime.now(); final difference = now.difference(dateTime); if (difference.inSeconds < 60) { return 'همین الان'; } else if (difference.inMinutes < 60) { return '${difference.inMinutes} دقیقه قبل'; } else if (difference.inHours < 24) { return '${difference.inHours} ساعت قبل'; } else if (difference.inDays < 7) { return '${difference.inDays} روز قبل'; } else { return DateFormat('yyyy/MM/dd', 'fa').format(dateTime); } } void _navigateToOffer(NotificationModel notification) { if (!notification.status) return; final offersState = context.read().state; if (offersState is OffersLoadSuccess) { try { final offer = offersState.offers.firstWhere((o) => o.id == notification.discountId); Navigator.of(context).push( MaterialPageRoute( builder: (_) => ProductDetailPage(offer: offer), ), ); } catch (e) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('این تخفیف در حال حاضر در دسترس نیست.')), ); } } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('اطلاعات تخفیف‌ها هنوز بارگذاری نشده است.')), ); } } @override Widget build(BuildContext context) { return Column( children: [ Expanded( child: _buildBody(), ), ], ); } Widget _buildBody() { if (_isLoading) { return const Center(child: CircularProgressIndicator()); } if (_errorMessage.isNotEmpty) { return Center( child: Padding( padding: const EdgeInsets.all(16.0), child: Text(_errorMessage, textAlign: TextAlign.center), ), ); } if (_notifications.isEmpty) { return const Center( child: Padding( padding: EdgeInsets.all(16.0), child: Text('اعلانی وجود ندارد.', textAlign: TextAlign.center), ), ); } return ListView.builder( padding: const EdgeInsets.symmetric(vertical: 0.0), itemCount: _notifications.length, itemBuilder: (context, index) { return _buildNotificationCard(_notifications[index]); }, ); } Widget _buildNotificationCard(NotificationModel notification) { final bool isExpired = !notification.status; final Color textColor = isExpired ? Colors.grey.shade600 : Colors.black; return Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( notification.description, style: TextStyle(fontSize: 15, height: 1.6, color: textColor), ), const SizedBox(height: 16), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( _formatTimeAgo(notification.createdAt.toLocal()), style: TextStyle(color: Colors.grey.shade600, fontSize: 12), ), if (isExpired) ElevatedButton( onPressed: null, style: ElevatedButton.styleFrom( backgroundColor: Colors.grey.shade300, foregroundColor: Colors.grey.shade700, elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), padding: const EdgeInsets.symmetric(horizontal: 16), ), child: const Text('تخفیف تمام شد'), ) else Row( children: [ TextButton( onPressed: () => _ignoreNotification(notification.id), style: TextButton.styleFrom(foregroundColor: Colors.red.shade700), child: const Text('بیخیال'), ), const SizedBox(width: 4), ElevatedButton( onPressed: () => _navigateToOffer(notification), style: ElevatedButton.styleFrom( backgroundColor: AppColors.backgroundConfirm, foregroundColor: AppColors.selectedImg, side: BorderSide(color: Colors.green.shade200), elevation: 0, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), padding: const EdgeInsets.symmetric(horizontal: 16), ), child: const Text('بزن بریم'), ), ], ), ], ), ], ), ); } }