import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:generp/Utils/GlobalConstants.dart'; import 'package:generp/screens/hrm/AddManualAttendance.dart'; import 'package:generp/screens/hrm/AttendanceRequestDetail.dart'; import 'package:provider/provider.dart'; import '../../Notifiers/hrmProvider/attendanceListProvider.dart'; import '../../Models/hrmModels/attendanceRequestListResponse.dart'; import '../../Utils/app_colors.dart'; import '../commonDateRangeFilter.dart'; import 'AddLiveAttendance.dart'; import 'package:intl/intl.dart'; Map getDateRange(String selectedDate) { final now = DateTime.now(); final formatter = DateFormat("yyyy-MM-dd"); late DateTime from; late DateTime to; switch (selectedDate) { case "All": from = now; to = now; break; case "Today": from = now; to = now; break; case "Yesterday": from = now.subtract(const Duration(days: 1)); to = now.subtract(const Duration(days: 1)); break; case "This Month": from = DateTime(now.year, now.month, 1); to = DateTime(now.year, now.month + 1, 0); break; case "Past 7 days": from = now.subtract(const Duration(days: 6)); to = now; break; case "Last Month": from = DateTime(now.year, now.month - 1, 1); to = DateTime(now.year, now.month, 0); break; case "Custom": // For custom, you should open a date picker dialog from = now; // Placeholder to = now; // Placeholder break; default: from = now; to = now; } return { "from": formatter.format(from), "to": formatter.format(to), }; } class Attendancelist extends StatefulWidget { const Attendancelist({super.key}); @override State createState() => _AttendancelistState(); } class _AttendancelistState extends State { String selectedType = "All"; String selectedDate = "Today"; final List typeOptions = ["All", "Check In", "Check Out","Check In/Out"]; final List dateOptions = [ "Today", "Yesterday", "This Month", "Past 7 days", "Last Month", "Custom", ]; @override Widget build(BuildContext context) { final dateRange = getDateRange(selectedDate); final fromDate = dateRange["from"]!; final toDate = dateRange["to"]!; final type = (selectedType == "All") ? "" : selectedType; return SafeArea( top: false, child: ChangeNotifierProvider( create: (_) => Attendancelistprovider()..fetchAttendanceRequests(context, type, "", ""), child: Consumer( builder: (context, provider, child) { return Scaffold( appBar: AppBar( automaticallyImplyLeading: false, backgroundColor: Colors.white, title: Row( children: [ InkResponse( onTap: () => Navigator.pop(context, true), child: SvgPicture.asset( "assets/svg/appbar_back_button.svg", height: 25, ), ), const SizedBox(width: 10), Text( "Attendance List", style: TextStyle( fontSize: 18, fontFamily: "Plus Jakarta Sans", fontWeight: FontWeight.w600, color: AppColors.semi_black, ), ), ], ), actions: [ InkResponse( onTap: () { showModalBottomSheet( context: context, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(16)), ), builder: (context) { return StatefulBuilder( builder: (context, setModalState) { return Padding( padding: const EdgeInsets.all(16), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Filter Attendance", style: TextStyle( fontSize: 17, fontWeight: FontWeight.bold, color: Colors.blue, fontFamily: "Plus Jakarta Sans" ), ), const SizedBox(height: 16), /// Type Dropdown Text("Type", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w400, fontFamily: "Plus Jakarta Sans" ) ), SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 2), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), ), child: DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, hint: const Text( "Select Type", style: TextStyle(fontSize: 14), overflow: TextOverflow.ellipsis, ), value: selectedType, items: typeOptions .map((type) => DropdownMenuItem( value: type, child: Text(type), )) .toList(), onChanged: (val) { setModalState(() { selectedType = val!; }); }, buttonStyleData: const ButtonStyleData( height: 52, padding: EdgeInsets.zero, ), dropdownStyleData: DropdownStyleData( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), ), ), ), ), ), const SizedBox(height: 18), /// Date Dropdown const Text("Date", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w400, fontFamily: "Plus Jakarta Sans" )), const SizedBox(height: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 2), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(8), ), child: DropdownButtonHideUnderline( child: DropdownButton2( isExpanded: true, hint: const Text( "Select Date", style: TextStyle(fontSize: 14), overflow: TextOverflow.ellipsis, ), value: selectedDate, items: dateOptions .map((date) => DropdownMenuItem( value: date, child: Text(date), )) .toList(), onChanged: (val) { setModalState(() { selectedDate = val!; }); }, buttonStyleData: const ButtonStyleData( height: 52, padding: EdgeInsets.zero, ), dropdownStyleData: DropdownStyleData( decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), ), ), ), ), ), const SizedBox(height: 26), Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Expanded( child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blue, padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: () { // on apply provider.fetchAttendanceRequests(context, selectedType, "", ""); Navigator.pop(context); }, child: const Text( "Apply", style: TextStyle( fontFamily: "Plus Jakarta Sans", color: Colors.white, fontWeight: FontWeight.w600, ), ), ), ), const SizedBox(width: 12), Expanded( child: OutlinedButton( style: OutlinedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 14), side: BorderSide(color: Colors.grey.shade400), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: () { // on cancel Navigator.pop(context); }, child: const Text( "Cancel", style: TextStyle( fontFamily: "Plus Jakarta Sans", color: Colors.black87, fontWeight: FontWeight.w600, ), ), ), ), ], ), const SizedBox(height: 22), ], ), ); }, ); }, ); }, child: SvgPicture.asset( "assets/svg/filter_ic.svg", height: 25, ), ), const SizedBox(width: 20), ], ), backgroundColor: const Color(0xFFF6F6F8), body: Column( children: [ /// Attendance list Expanded( child: Builder( builder: (context) { if (provider.isLoading) { return const Center(child: CircularProgressIndicator(color: Colors.blue,)); } if (provider.errorMessage != null) { return Center(child: Text(provider.errorMessage!)); } if (provider.response?.requestList == null || provider.response!.requestList!.isEmpty) { return const Center(child: Text("No requests found")); } final list = provider.response!.requestList!; return ListView.builder( padding: const EdgeInsets.all(8), itemCount: list.length, itemBuilder: (context, index) { final item = list[index]; final initials = _generateInitials(item); return InkWell( borderRadius: BorderRadius.circular(16), onTap: () { /// navigation flow Navigator.push( context, MaterialPageRoute( builder: (context) => AttendanceRequestDetailScreen( attendanceListId: item.id, ), ), ); }, child: Container( margin: const EdgeInsets.symmetric(horizontal: 8.5, vertical: 5), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8.5), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), ), child: Row( children: [ /// Left Avatar Circle Container( height: 48, width: 50, padding: const EdgeInsets.all(8.0), decoration: BoxDecoration( color: _getAvatarColor(item.status), shape: BoxShape.circle, ), child: Center( child: Text( getText(item.status), style: TextStyle( color: _getTextColor(item.status), fontSize: 14, fontWeight: FontWeight.bold, ), ), ), ), const SizedBox(width: 10), /// Middle Section Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( item.type ?? "-", maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 15, color: Color(0xff2D2D2D), fontFamily: "Plus Jakarta Sans", fontStyle: FontStyle.normal, fontWeight: FontWeight.w400 ), ), Text( item.date ?? "-", style: const TextStyle( fontSize: 12.5, color: Color(0xff818181), fontFamily: "Plus Jakarta Sans", fontStyle: FontStyle.normal, fontWeight: FontWeight.w400 ), ), ], ), ), /// Right Status (Live / Manual) Text( item.attendanceType ?? "-", textAlign: TextAlign.right, style: TextStyle( fontFamily: "Plus Jakarta Sans", fontSize: 14, fontWeight: FontWeight.w500, color: (item.attendanceType ?? "").toLowerCase() == "live" ? Colors.green : Colors.orange, ), ), ], ), ), ); }, ); }, ), ) ], ), bottomNavigationBar: Container( alignment: Alignment.bottomCenter, height: 65, decoration: const BoxDecoration(color: Colors.white), child: Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ Expanded( child: InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => AddLiveAttendanceScreen(), settings: const RouteSettings( name: 'AddLiveAttendanceScreen', ), ), ).then((_) { }); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset("assets/svg/hrm/live.svg"), const SizedBox(width: 10), Text("Live Request", style: TextStyle(color: AppColors.semi_black)), ], ), ), ), const SizedBox(width: 10), SvgPicture.asset("assets/svg/crm/vertical_line_ic.svg"), const SizedBox(width: 10), Expanded( child: InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => const AddManualAttendanceScreen(), settings: const RouteSettings( name: 'AddManualAttendanceScreen'), ), ).then((_) { }); }, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ SvgPicture.asset("assets/svg/hrm/manual.svg"), const SizedBox(width: 10), Text("Manual Request", style: TextStyle(color: AppColors.semi_black)), ], ), ), ), ], ), ), ); }, ), ), ); } /// Generate avatar initials like L1A, L1R String _generateInitials(RequestList item) { final attType = (item.attendanceType?.isNotEmpty ?? false) ? item.attendanceType![0].toUpperCase() : "U"; final type = (item.type?.isNotEmpty ?? false) ? item.type![0].toUpperCase() : "X"; return "$attType$type"; } /// Avatar color generator Color _getAvatarColor(value) { var color = AppColors.approved_bg_color; switch (value) { case 'Requested': return AppColors.requested_bg_color; case 'Level 1 Approved': return AppColors.approved_bg_color; case 'Level 1 Rejected': return AppColors.rejected_bg_color; case 'Level 2 Approved': return AppColors.approved_bg_color; case 'Level 2 Rejected': return AppColors.rejected_bg_color; case 'Updated': return AppColors.processed_bg_color; case 'Payment Rejected': return AppColors.rejected_bg_color; } return color; } Color _getTextColor(value) { var color = AppColors.approved_text_color; switch (value) { case 'Requested': return AppColors.requested_text_color; case 'Level 1 Approved': return AppColors.approved_text_color; case 'Level 1 Rejected': return AppColors.rejected_text_color; case 'Level 2 Approved': return AppColors.approved_text_color; case 'Level 2 Rejected': return AppColors.rejected_text_color; case 'Updated': return AppColors.processed_text_color; } return color; } getText(value) { switch (value) { case 'Requested': return "R"; case 'Level 1 Approved': return "L1A"; case 'Level 1 Rejected': return "L1R"; case 'Level 2 Approved': return "L2A"; case 'Level 2 Rejected': return "L2R"; case 'Updated': return "U"; default: return "Requested"; } } }