import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../core/theme/app_theme.dart'; import '../../core/widgets/error_view.dart'; import '../../shared/models/leave_request.dart'; import 'leave_provider.dart'; class LeaveListScreen extends ConsumerWidget { const LeaveListScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final async = ref.watch(leaveListProvider); return Scaffold( appBar: AppBar(title: const Text('Leave Requests')), body: async.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => ErrorView( message: e.toString(), onRetry: () => ref.invalidate(leaveListProvider), ), data: (requests) { final pending = requests.where((r) => r.status == 'pending').toList(); final all = requests; return RefreshIndicator( color: AppColors.primary, onRefresh: () async => ref.invalidate(leaveListProvider), child: requests.isEmpty ? ListView(children: const [ SizedBox(height: 120), Center( child: Column(children: [ Icon(Icons.event_busy, size: 48, color: AppColors.textSub), SizedBox(height: 12), Text('No leave requests', style: TextStyle(color: AppColors.textSub)), ]), ), ]) : ListView( padding: const EdgeInsets.fromLTRB(16, 16, 16, 100), children: [ // Pending section if (pending.isNotEmpty) ...[ Row(children: [ const Icon(Icons.pending_actions, size: 16, color: AppColors.warning), const SizedBox(width: 6), Text('Pending (${pending.length})', style: const TextStyle( fontWeight: FontWeight.w700, fontSize: 13, color: AppColors.warning, )), ]), const SizedBox(height: 8), ...pending.map((r) => Padding( padding: const EdgeInsets.only(bottom: 10), child: _PendingCard(request: r, onRefresh: () => ref.invalidate(leaveListProvider)), )), const SizedBox(height: 16), Row(children: [ const Icon(Icons.list_alt, size: 16, color: AppColors.textSub), const SizedBox(width: 6), const Text('All Requests', style: TextStyle(fontWeight: FontWeight.w700, fontSize: 13, color: AppColors.textSub)), const SizedBox(width: 8), Expanded(child: Divider(color: AppColors.border)), ]), const SizedBox(height: 8), ], // All requests ...all.map((r) => Padding( padding: const EdgeInsets.only(bottom: 8), child: _LeaveCard(request: r), )), ], ), ); }, ), ); } } // ── Pending card (with Approve / Reject buttons) ────────────────────────────── class _PendingCard extends StatefulWidget { final LeaveRequest request; final VoidCallback onRefresh; const _PendingCard({required this.request, required this.onRefresh}); @override State<_PendingCard> createState() => _PendingCardState(); } class _PendingCardState extends State<_PendingCard> { bool _loading = false; Future _review(BuildContext context, bool approve) async { final notesCtrl = TextEditingController(); final confirmed = await showModalBottomSheet( context: context, isScrollControlled: true, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), builder: (ctx) => Padding( padding: EdgeInsets.only( left: 20, right: 20, top: 20, bottom: MediaQuery.of(ctx).viewInsets.bottom + 20, ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ Icon(approve ? Icons.check_circle_outline : Icons.cancel_outlined, color: approve ? AppColors.primary : AppColors.danger), const SizedBox(width: 8), Text(approve ? 'Approve Request' : 'Reject Request', style: const TextStyle(fontWeight: FontWeight.w700, fontSize: 16)), ]), const SizedBox(height: 12), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.bg, borderRadius: BorderRadius.circular(8), ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(widget.request.username, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 13)), const SizedBox(height: 2), Text('${widget.request.startDate} → ${widget.request.endDate} (${widget.request.durationDays}d)', style: const TextStyle(fontSize: 12, color: AppColors.textSub)), const SizedBox(height: 4), Text(widget.request.reason, style: const TextStyle(fontSize: 13, color: AppColors.text)), ]), ), const SizedBox(height: 12), TextField( controller: notesCtrl, decoration: const InputDecoration( labelText: 'Notes (optional)', hintText: 'Add a note for the employee...', ), maxLines: 2, ), const SizedBox(height: 16), Row(children: [ Expanded( child: OutlinedButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('Cancel'), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: approve ? AppColors.primary : AppColors.danger, foregroundColor: Colors.white, ), onPressed: () => Navigator.pop(ctx, true), child: Text(approve ? 'Approve' : 'Reject'), ), ), ]), ], ), ), ); if (confirmed != true || !mounted) return; setState(() => _loading = true); try { if (approve) { await approveLeave(widget.request.id, adminNotes: notesCtrl.text.trim().isEmpty ? null : notesCtrl.text.trim()); } else { await rejectLeave(widget.request.id, adminNotes: notesCtrl.text.trim().isEmpty ? null : notesCtrl.text.trim()); } widget.onRefresh(); } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('Failed: $e'), backgroundColor: AppColors.danger), ); } } finally { if (mounted) setState(() => _loading = false); } } @override Widget build(BuildContext context) { final r = widget.request; return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: const Color(0xFFFCD34D).withOpacity(0.6)), boxShadow: [BoxShadow(color: Colors.black.withOpacity(0.04), blurRadius: 4, offset: const Offset(0, 2))], ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ CircleAvatar( radius: 14, backgroundColor: AppColors.textSub.withOpacity(0.15), child: Text(r.username[0].toUpperCase(), style: const TextStyle(fontSize: 12, fontWeight: FontWeight.w700, color: AppColors.text)), ), const SizedBox(width: 8), Expanded( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(r.username, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 14)), Text('${r.startDate} → ${r.endDate} · ${r.durationDays} day${r.durationDays != 1 ? 's' : ''}', style: const TextStyle(fontSize: 12, color: AppColors.textSub)), ]), ), _StatusBadge(r.status), ]), const SizedBox(height: 8), Text(r.reason, style: const TextStyle(fontSize: 13, color: AppColors.text)), const SizedBox(height: 12), if (_loading) const Center(child: SizedBox(width: 24, height: 24, child: CircularProgressIndicator(strokeWidth: 2))) else Row(children: [ Expanded( child: OutlinedButton.icon( onPressed: () => _review(context, false), icon: const Icon(Icons.close, size: 16), label: const Text('Reject'), style: OutlinedButton.styleFrom( foregroundColor: AppColors.danger, side: const BorderSide(color: AppColors.danger), ), ), ), const SizedBox(width: 10), Expanded( child: ElevatedButton.icon( onPressed: () => _review(context, true), icon: const Icon(Icons.check, size: 16), label: const Text('Approve'), style: ElevatedButton.styleFrom( backgroundColor: AppColors.primary, foregroundColor: Colors.white, ), ), ), ]), ]), ); } } // ── Regular leave card (read-only) ──────────────────────────────────────────── class _LeaveCard extends StatelessWidget { final LeaveRequest request; const _LeaveCard({required this.request}); @override Widget build(BuildContext context) { final r = request; return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), border: Border.all(color: AppColors.border), ), child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Row(children: [ CircleAvatar( radius: 13, backgroundColor: AppColors.textSub.withOpacity(0.15), child: Text(r.username[0].toUpperCase(), style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w700, color: AppColors.text)), ), const SizedBox(width: 8), Expanded( child: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(r.username, style: const TextStyle(fontWeight: FontWeight.w600, fontSize: 13)), Text('${r.startDate} → ${r.endDate} · ${r.durationDays}d', style: const TextStyle(fontSize: 11, color: AppColors.textSub)), ]), ), _StatusBadge(r.status), ]), const SizedBox(height: 6), Text(r.reason, style: const TextStyle(fontSize: 12, color: AppColors.text), maxLines: 2, overflow: TextOverflow.ellipsis), if (r.adminNotes != null && r.adminNotes!.isNotEmpty) ...[ const SizedBox(height: 6), Row(children: [ const Icon(Icons.notes, size: 12, color: AppColors.textSub), const SizedBox(width: 4), Expanded( child: Text(r.adminNotes!, style: const TextStyle(fontSize: 11, color: AppColors.textSub, fontStyle: FontStyle.italic), maxLines: 2, overflow: TextOverflow.ellipsis), ), ]), ], ]), ); } } // ── Status badge ────────────────────────────────────────────────────────────── class _StatusBadge extends StatelessWidget { final String status; const _StatusBadge(this.status); @override Widget build(BuildContext context) { final (color, bg) = switch (status) { 'approved' => (Colors.white, AppColors.primary), 'rejected' => (Colors.white, AppColors.danger), _ => (const Color(0xFF92400E), const Color(0xFFFEF3C7)), // pending }; return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration(color: bg, borderRadius: BorderRadius.circular(20)), child: Text(status, style: TextStyle(fontSize: 10, fontWeight: FontWeight.w700, color: color)), ); } }