import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../widgets/app_background.dart'; import '../widgets/settings_bar.dart'; import '../widgets/onboarding_button.dart'; import '../../models/leave_request.dart'; import '../../core/services/request_service.dart'; import '../../core/di/injection_container.dart'; import '../../data/datasources/user_local_data_source.dart'; import '../../domain/usecases/create_vacation_usecase.dart'; import '../../domain/usecases/get_vacation_types_usecase.dart'; import '../../domain/models/vacation_request.dart'; import '../../domain/models/vacation_type_model.dart'; import '../../core/error/failures.dart'; class RequestLeaveScreen extends StatefulWidget { const RequestLeaveScreen({super.key}); @override State createState() => _RequestLeaveScreenState(); } class _RequestLeaveScreenState extends State { // Dropdown value - initialize with default String leaveType = "إجازة مرضية"; // Toggle switch bool isTimedLeave = false; // Date & time selectors DateTime? fromDate = DateTime.now(); DateTime? toDate = DateTime.now(); TimeOfDay? fromTime = const TimeOfDay(hour: 12, minute: 00); TimeOfDay? toTime = const TimeOfDay(hour: 12, minute: 00); // Text controller for reason final TextEditingController reasonController = TextEditingController(); // Use the singleton instance final RequestService _requestService = RequestService(); // Use cases final CreateVacationUseCase _createVacationUseCase = sl(); final GetVacationTypesUseCase _getVacationTypesUseCase = sl(); // Vacation types from API List _vacationTypes = []; // Store selected type value instead of string int? _selectedVacationTypeValue; @override void initState() { super.initState(); _loadVacationTypes(); } // ------------------------------- // STEP A: single helper for selecting type safely // ------------------------------- void _setSelectedVacationType(int value) { _selectedVacationTypeValue = value; if (_vacationTypes.isNotEmpty) { final selectedType = _vacationTypes.firstWhere( (t) => t.value == value, orElse: () => _vacationTypes.first, ); leaveType = _getArabicName(selectedType.name); } else { // Fallback text (when API not loaded yet) if (value == 0) leaveType = "إجازة زمنية"; if (value == 1) leaveType = "إجازة مرضية"; if (value == 2) leaveType = "إجازة مدفوعة"; if (value == 3) leaveType = "إجازة غير مدفوعة"; } } // ------------------------------- // STEP B: single helper for timed leave rule // ------------------------------- void _setTimedLeave(bool on) { setState(() { isTimedLeave = on; if (isTimedLeave) { // FORCE TimeOff (value = 1) _setSelectedVacationType(0); // Optional: keep dates consistent for timed leave (same day) toDate = fromDate; } }); } Future _loadVacationTypes() async { final result = await _getVacationTypesUseCase(); result.fold( (failure) { print('Failed to load vacation types: ${_getFailureMessage(failure)}'); }, (response) { if (!mounted) return; setState(() { _vacationTypes = response.data; if (_vacationTypes.isEmpty) return; // IMPORTANT: // If toggle already ON -> force TimeOff if (isTimedLeave) { final timeOff = _vacationTypes.firstWhere( (t) => t.value == 1, orElse: () => _vacationTypes.first, ); _setSelectedVacationType(timeOff.value); } else { // Otherwise default to SickLeave (2) if available final sickLeave = _vacationTypes.firstWhere( (type) => type.value == 2, orElse: () => _vacationTypes.first, ); _setSelectedVacationType(sickLeave.value); } }); }, ); } String _getArabicName(String apiName) { switch (apiName) { case 'TimeOff': return 'إجازة زمنية'; case 'SickLeave': return 'إجازة مرضية'; case 'PaidLeave': return 'إجازة مدفوعة'; case 'UnpaidLeave': return 'إجازة غير مدفوعة'; default: return apiName; } } int _getVacationTypeValue() { if (_selectedVacationTypeValue != null) { return _selectedVacationTypeValue!; } if (leaveType.contains("مرضية") || leaveType == "SickLeave") { return 1; } else if (leaveType.contains("مدفوعة") && !leaveType.contains("غير")) { return 2; } else if (leaveType.contains("غير مدفوعة") || leaveType == "UnpaidLeave") { return 3; } else if (leaveType.contains("زمنية") || leaveType == "TimeOff") { return 0; } return 1; } String _getFailureMessage(Failure failure) { if (failure is ServerFailure) return failure.message; if (failure is NetworkFailure) return failure.message; return 'حدث خطأ غير متوقع'; } /// PICK DATE Future pickDate(bool isFrom) async { DateTime initial = isFrom ? fromDate! : toDate!; DateTime? newDate = await showDatePicker( context: context, initialDate: initial, firstDate: DateTime(2020), lastDate: DateTime(2035), builder: (context, child) => Theme(data: ThemeData.dark(), child: child!), ); if (newDate != null) { setState(() { if (isFrom) { fromDate = newDate; // If timed leave, keep toDate same as fromDate if (isTimedLeave) toDate = newDate; } else { toDate = newDate; } }); } } /// PICK TIME Future pickTime(bool isFrom) async { TimeOfDay initial = isFrom ? fromTime! : toTime!; TimeOfDay? newTime = await showTimePicker( context: context, initialTime: initial, builder: (context, child) => Theme(data: ThemeData.dark(), child: child!), ); if (newTime != null) { setState(() { if (isFrom) { fromTime = newTime; } else { toTime = newTime; } }); } } Future _saveLeaveRequest() async { if (reasonController.text.isEmpty) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('الرجاء إدخال السبب'), backgroundColor: Colors.red, ), ); } return; } final employeeId = await sl().getCachedEmployeeId(); if (employeeId == null) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('خطأ: لم يتم العثور على رقم الموظف'), backgroundColor: Colors.red, ), ); } return; } DateTime finalStartDate = fromDate!; DateTime finalEndDate = toDate!; if (isTimedLeave) { finalStartDate = DateTime( fromDate!.year, fromDate!.month, fromDate!.day, fromTime!.hour, fromTime!.minute, ); finalEndDate = DateTime( fromDate!.year, fromDate!.month, fromDate!.day, toTime!.hour, toTime!.minute, ); } else { finalStartDate = DateTime(fromDate!.year, fromDate!.month, fromDate!.day); finalEndDate = DateTime(toDate!.year, toDate!.month, toDate!.day); } final typeValue = _getVacationTypeValue(); if (mounted) { showDialog( context: context, barrierDismissible: false, builder: (context) => const Center(child: CircularProgressIndicator()), ); } try { final vacationRequest = VacationRequest( employeeId: employeeId, startDate: finalStartDate, endDate: finalEndDate, reason: reasonController.text, type: typeValue, ); final result = await _createVacationUseCase(vacationRequest); if (!mounted) return; Navigator.pop(context); result.fold( (failure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(_getFailureMessage(failure)), backgroundColor: Colors.red, ), ); }, (response) { final leaveRequest = LeaveRequest( id: response.data?.id ?? DateTime.now().millisecondsSinceEpoch.toString(), leaveType: leaveType, isTimedLeave: isTimedLeave, fromDate: fromDate!, toDate: toDate!, fromTime: fromTime!, toTime: toTime!, reason: reasonController.text, requestDate: DateTime.now(), status: "waiting", ); _requestService.addLeaveRequest(leaveRequest); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('تم إرسال طلب الأجازة بنجاح'), backgroundColor: Colors.green, ), ); Navigator.pop(context); }, ); } catch (e) { if (mounted) { Navigator.pop(context); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('حدث خطأ غير متوقع: $e'), backgroundColor: Colors.red, ), ); } } } @override Widget build(BuildContext context) { return Scaffold( resizeToAvoidBottomInset: true, body: AppBackground( child: SafeArea( child: Column( children: [ SettingsBar( selectedIndex: -1, onTap: (_) {}, showBackButton: true, onBackTap: () => Navigator.pop(context), iconPaths: const [ "assets/images/user.svg", "assets/images/bell.svg", ], ), Flexible( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 25), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Align( alignment: Alignment.topRight, child: Text( "طلب أجازة ", style: TextStyle( color: Colors.white, fontSize: 28, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 10), Align( alignment: Alignment.centerRight, child: const Text( "نوع الإجازة", style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600, ), ), ), const SizedBox(height: 5), Directionality( textDirection: TextDirection.rtl, child: Opacity( opacity: isTimedLeave ? 0.45 : 1.0, child: IgnorePointer( ignoring: isTimedLeave, child: Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: 20, ), height: 58, decoration: BoxDecoration( color: isTimedLeave ? Colors.grey[300] : Colors.white, borderRadius: BorderRadius.circular(14), boxShadow: const [ BoxShadow( color: Color(0x22000000), blurRadius: 8, offset: Offset(0, 3), ), ], ), child: DropdownButtonHideUnderline( child: _vacationTypes.isEmpty ? const Center( child: Padding( padding: EdgeInsets.all(8.0), child: CircularProgressIndicator(), ), ) : DropdownButton( value: _selectedVacationTypeValue, icon: const Icon( Icons.keyboard_arrow_down_rounded, color: Colors.black, size: 28, ), style: const TextStyle( color: Colors.black, fontSize: 17, ), isExpanded: true, onChanged: (value) { if (value == null) return; setState(() { _setSelectedVacationType(value); }); // Sync toggle with selection if (value == 0 && !isTimedLeave) { _setTimedLeave(true); } else if (value != 0 && isTimedLeave) { setState( () => isTimedLeave = false, ); } }, items: _vacationTypes.map((type) { final arabicName = _getArabicName(type.name); return DropdownMenuItem( value: type.value, child: Directionality( textDirection: TextDirection.rtl, child: Align( alignment: Alignment .centerRight, child: Text(arabicName), ), ), ); }).toList(), ), ), ), ), ), ), const SizedBox(height: 25), GestureDetector( onTap: () { _setTimedLeave(!isTimedLeave); }, child: Row( children: [ AnimatedContainer( duration: const Duration(milliseconds: 250), width: 75, height: 30, padding: const EdgeInsets.symmetric( horizontal: 4, ), decoration: BoxDecoration( color: isTimedLeave ? const Color(0xFF0A6B4A) : const Color(0xFF9E9E9E), borderRadius: BorderRadius.circular(40), ), child: Align( alignment: isTimedLeave ? Alignment.centerRight : Alignment.centerLeft, child: AnimatedContainer( duration: const Duration(milliseconds: 250), width: 30, height: 30, decoration: BoxDecoration( color: isTimedLeave ? const Color(0xFF12BE85) : Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: const Color(0x2D000000), blurRadius: 6, offset: const Offset(0, 2), ), ], ), ), ), ), const SizedBox(width: 14), Container( width: 10, height: 10, decoration: const BoxDecoration( color: Color(0xFF32C59A), shape: BoxShape.circle, ), ), const SizedBox(width: 6), Expanded( child: Container( height: 2, color: const Color(0xFF32C59A), ), ), const SizedBox(width: 12), const Text( "إجازة زمنية", style: TextStyle( color: Colors.white, fontSize: 19, fontWeight: FontWeight.w600, ), ), ], ), ), const SizedBox(height: 20), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFFF4F4F4), borderRadius: BorderRadius.circular(16), boxShadow: const [ BoxShadow( color: Color(0x33000000), blurRadius: 10, offset: Offset(0, 4), ), ], ), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.end, children: [ const Text( "فترة الإجازة", style: TextStyle( color: Colors.black, fontSize: 18, fontWeight: FontWeight.bold, ), ), const SizedBox(width: 8), SvgPicture.asset( "assets/images/calendar.svg", width: 24, height: 24, color: const Color(0xFF007C46), ), ], ), const SizedBox(height: 15), _dateRow( label: "من", date: fromDate!, time: fromTime!, onDateTap: isTimedLeave ? null : () => pickDate(true), onTimeTap: () => pickTime(true), ), const SizedBox(height: 15), _dateRow( label: "الى", date: toDate!, time: toTime!, onDateTap: isTimedLeave ? null : () => pickDate(false), onTimeTap: () => pickTime(false), ), ], ), ), const SizedBox(height: 10), Align( alignment: Alignment.centerRight, child: Directionality( textDirection: TextDirection.rtl, child: const Text( "السبب", style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.w600, ), ), ), ), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( border: Border.all( color: const Color(0xFF00FFAA), width: 0.5, ), borderRadius: BorderRadius.circular(14), ), child: Container( height: 70, padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 10, ), decoration: BoxDecoration( color: const Color(0xFFEAEAEA), borderRadius: BorderRadius.circular(12), ), child: Directionality( textDirection: TextDirection.rtl, child: TextField( controller: reasonController, maxLines: 5, textAlign: TextAlign.right, decoration: const InputDecoration( border: InputBorder.none, hintText: "اكتب السبب", hintStyle: TextStyle(color: Colors.grey), ), ), ), ), ), const SizedBox(height: 20), Center( child: OnboardingButton( text: "تأكيد الطلب", backgroundColor: const Color(0xFFD1FEF0), textColor: Colors.black, onPressed: _saveLeaveRequest, ), ), ], ), ), ), ), ], ), ), ), ); } Widget _dateRow({ required String label, required DateTime date, required TimeOfDay time, required VoidCallback? onDateTap, required VoidCallback onTimeTap, }) { bool dateDisabled = onDateTap == null; return Container( padding: const EdgeInsets.symmetric(horizontal: 12), height: 55, decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), ), child: Row( children: [ Opacity( opacity: dateDisabled ? 0.45 : 1, child: IgnorePointer( ignoring: dateDisabled, child: GestureDetector( onTap: onDateTap, child: Row( children: [ const Icon(Icons.arrow_drop_down), const SizedBox(width: 4), Text( "${date.year}-${date.month}-${date.day}", style: const TextStyle(fontSize: 16), ), const SizedBox(width: 10), Text( _weekday(date.weekday), style: const TextStyle(fontSize: 16), ), ], ), ), ), ), const Spacer(), GestureDetector( onTap: onTimeTap, child: Text( "${time.hour}:${time.minute.toString().padLeft(2, '0')}", style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), ), const SizedBox(width: 10), Text( label, style: const TextStyle(color: Colors.black, fontSize: 15), ), ], ), ); } // NOTE: DateTime.weekday is 1..7 (Mon..Sun) String _weekday(int day) { switch (day) { case 7: return "الأحد"; case 1: return "الإثنين"; case 2: return "الثلاثاء"; case 3: return "الأربعاء"; case 4: return "الخميس"; case 5: return "الجمعة"; case 6: return "السبت"; default: return ""; } } }