import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../../blocs/notification_bloc/notification_bloc.dart'; class NotificationPanel extends StatelessWidget { const NotificationPanel({super.key}); @override Widget build(BuildContext context) { return BlocBuilder( builder: (context, state) { final alerts = state.activeAlerts; return Container( margin: const EdgeInsets.fromLTRB(12, 4, 12, 0), decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(16), border: Border.all( color: Theme.of(context).colorScheme.outlineVariant, width: 0.5, ), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.08), blurRadius: 16, offset: const Offset(0, 4), ), ], ), child: Column( mainAxisSize: MainAxisSize.min, children: [ _PanelHeader(unreadCount: state.unreadCount), if (alerts.isEmpty) const _EmptyState() else ListView.separated( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, itemCount: alerts.length, separatorBuilder: (_, __) => Divider( height: 1, color: Theme.of(context).colorScheme.outlineVariant, ), itemBuilder: (context, i) => _AlertTile(alert: alerts[i]), ), ], ), ); }, ); } } class _PanelHeader extends StatelessWidget { final int unreadCount; const _PanelHeader({required this.unreadCount}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( children: [ const Text( 'Notifikasi', style: TextStyle(fontWeight: FontWeight.w600, fontSize: 14), ), if (unreadCount > 0) ...[ const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: Colors.red.shade600, borderRadius: BorderRadius.circular(10), ), child: Text( '$unreadCount baru', style: const TextStyle( color: Colors.white, fontSize: 10, fontWeight: FontWeight.w600, ), ), ), ], const Spacer(), if (unreadCount > 0) TextButton( onPressed: () => context .read() .add(const NotificationsMarkedAsRead()), style: TextButton.styleFrom( padding: const EdgeInsets.symmetric(horizontal: 8), minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), child: Text( 'Tandai dibaca', style: TextStyle(fontSize: 11, color: Colors.blue.shade700), ), ), ], ), ); } } class _EmptyState extends StatelessWidget { const _EmptyState(); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 24), child: Column( children: [ Icon(Icons.check_circle_outline, size: 32, color: Colors.green.shade400), const SizedBox(height: 8), Text( 'Semua sensor normal', style: TextStyle( fontSize: 13, color: Colors.grey.shade600, ), ), ], ), ); } } class _AlertTile extends StatelessWidget { final SensorAlert alert; const _AlertTile({required this.alert}); @override Widget build(BuildContext context) { final (color, icon) = switch (alert.severity) { AlertSeverity.danger => (Colors.red.shade600, Icons.warning_rounded), AlertSeverity.warning => (Colors.orange.shade600, Icons.info_outline), AlertSeverity.info => (Colors.blue.shade600, Icons.check_circle_outline), }; return InkWell( onTap: () => context .read() .add(NotificationDismissed(alert.sensorId)), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, color: color, size: 20), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( alert.sensorName, style: const TextStyle( fontWeight: FontWeight.w600, fontSize: 13, ), ), if (!alert.isRead) ...[ const SizedBox(width: 6), Container( width: 6, height: 6, decoration: BoxDecoration( color: color, shape: BoxShape.circle, ), ), ], ], ), const SizedBox(height: 2), Text( alert.message, style: TextStyle( fontSize: 12, color: Colors.grey.shade700, ), ), const SizedBox(height: 4), Text( _formatTime(alert.timestamp), style: TextStyle(fontSize: 11, color: Colors.grey.shade500), ), ], ), ), Icon(Icons.close, size: 14, color: Colors.grey.shade400), ], ), ), ); } String _formatTime(DateTime dt) { final now = DateTime.now(); final diff = now.difference(dt); if (diff.inMinutes < 1) return 'Baru saja'; if (diff.inMinutes < 60) return '${diff.inMinutes} menit lalu'; if (diff.inHours < 24) return '${diff.inHours} jam lalu'; return '${dt.day}/${dt.month} ${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}'; } }