import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:intl/intl.dart'; import 'package:shared_preferences/shared_preferences.dart'; import '../../../../core/responsive/responsive_builder.dart'; import '../../../../core/routing/routes.dart'; import '../../../../core/services/api_service.dart'; import '../../../providers/manager_provider.dart'; import '../../../providers/quotation_staff_proivder.dart'; import '../../../providers/userRoleProvider.dart'; import '../../staff/Enquiry/tabs/tab.dart'; import '../../staff/assignStaff.dart'; final enquiriesProvider = Provider>>((ref) { return List.generate(5, (i) { return { "reg": "rrTN64V4387", "Insurer": "rrNew India", "date": "rr09/09/2025", "time": "rr11:30 AM", }; }); }); String formatToCroresLakhsAndThousands(String value) { double numValue = double.parse(value); if (numValue >= 10000000) { return "₹ ${(numValue / 10000000).toStringAsFixed(2)} Crores"; } else if (numValue >= 100000) { return "₹ ${(numValue / 100000).toStringAsFixed(2)} Lakhs"; } else if (numValue >= 1000) { return "₹ ${(numValue / 1000).toStringAsFixed(2)} Thousands"; } else { return "₹ $numValue"; } } class LiveDashboard extends ConsumerStatefulWidget { const LiveDashboard({super.key}); @override ConsumerState createState() => _DashboardState(); } class _DashboardState extends ConsumerState { int selectedIndex = 1; int switcherStatus = 1; late ApiService apiService; String? policiesIssuedToday; String? policiesIssuedYear; String? policiesIssuedMonth; String? premiumValueToday; String? premiumValueYear; String? premiumValueMonth; String? earningsToday; String? earningsMonth; String? earningsYear; String? quotationsPendingCounts; // cross verify String? currentKey; // cross verify // List> dataVal = []; List> getStaffData = []; List> originalData = []; List> filteredData = []; int selectedTabIndex = 0; List> currentList = []; List> staffQuotationsPendingList = []; // cross verify List> quotationsPendingList = []; // cross verify List> policiesPendingList = []; // cross verify List> awaitingApprovalList = []; // cross verify List> unAssignedEnqList = []; // cross verify List> agentsPerformanceList = []; // cross verify List> nonAgentsPerformanceList = []; // cross verify dynamic prefid; dynamic prefroleId; bool isLoading = false; @override void initState() { super.initState(); apiService = ApiService(); Future.microtask(() { final prefmanagerid = ref.read(managerIdProvider); final prefuserid = ref.read(userIdProvider); final prefroleId = ref.read(userRoleProvider); print("B81 => roleId: $prefroleId | userId: $prefuserid "); if (prefuserid != null) { getStaffList(prefmanagerid!, prefroleId, prefuserid); } }); } void refresh() { print('___DASHBOARD___'); final prefmanagerid = ref.read(managerIdProvider); final prefuserid = ref.read(userIdProvider); final prefroleId = ref.read(userRoleProvider); if (prefuserid != null) { print("REFRESH- calling getStaffList with $prefmanagerid, $prefuserid"); getStaffList(prefmanagerid!, prefroleId, prefuserid); } } Future getExportExcel() async { final prefmanagerid = ref.read(managerIdProvider); final path = "staff_pending_summary"; final id = ''; final month = 'current'; try { final response = await apiService.generateChartExcel(path,id,month,prefmanagerid); return response; } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } // Future getExportExcel2(String status, String staffId) async { // final prefmanagerid = ref.read(managerIdProvider); // // // Use the parameters passed from the widget // final path = "staff_pending_summary_by_id"; // final id = staffId; // final month = status; // // try { // setState(() => isLoading = true); // // final response = await apiService.generateChartExcel( // path, // id, // month, // prefmanagerid // ); // // return response; // } catch (e) { // print('Export Error: $e'); // } finally { // if (mounted) setState(() => isLoading = false); // } // } Future handleEdit(String id) async { // Navigator.pop(context); print('EDITStaff'); print('EDITStaff - $id'); // dynamic id = data['id']; // context.go('/tabEnquiry/$id'); final prefs = await SharedPreferences.getInstance(); // ✅ Remove old value (if any) await prefs.remove('enqAgentDataId'); // setState(() { // final id = item['id'].toString(); // ✅ Save the new id // await prefs.setString('enqAgentDataId', id.toString()); await prefs.setString('enqAgentDataId', id); ref.read(enquiryIdProvider.notifier).state = id; context.go(AppRoutes.tabEnquiry); } Future handleStaffEdit(String id, String? flag) async { // Navigator.pop(context); ddd dynamic val; print('EDITStaff - $id'); if (flag == "Policies") { val = 'Policy'; } else { val = ''; } var enqId = id; final prefs = await SharedPreferences.getInstance(); // ✅ Remove old value (if any) await prefs.remove('enqStaffDataId'); // ✅ Save the new id await prefs.setString('enqStaffDataId', enqId.toString()); await prefs.setString('navFromDashboard', 'Dashboard'); ref.read(quotationStaffIdProvider.notifier).state = enqId; ref.read(navFromEnqStaffProvider.notifier).state = 'Dashboard'; // showDialog( // context: context, // builder: (context) => TabEnquiryStaffList(showKey: val), // ); final result = await showDialog( context: context, barrierDismissible: false, // optional - prevents closing by tapping outside builder: (context) => TabEnquiryStaffList(showKey: val), ); // ✅ Code here runs *after* the dialog is closed print("Dialog closed"); print("Dialog result: $result"); refresh(); } Future getStaffList(int managerId, role, userId) async { print('B89 => Fns called => $managerId | $role'); setState(() { isLoading = true; }); try { final response = await apiService.fetchDashboard(managerId, role, userId); if (response['status'] == 'success') { final data = response['data']; print('B99 => getStaffListData => ${response['data']}'); setState(() { // Policies Issued if (data['policies_issued'] != null) { policiesIssuedToday = data['policies_issued']['today']?.toString() ?? "0"; policiesIssuedYear = data['policies_issued']['year']?.toString() ?? "0"; policiesIssuedMonth = data['policies_issued']['month']?.toString() ?? "0"; } else { policiesIssuedToday = "0"; policiesIssuedYear = "0"; policiesIssuedMonth = "0"; } // Premium Value if (data['premium_value'] != null) { premiumValueToday = data['premium_value']['today']?.toString() ?? "0"; premiumValueYear = data['premium_value']['year']?.toString() ?? "0"; premiumValueMonth = data['premium_value']['month']?.toString() ?? "0"; } else { premiumValueToday = "0"; premiumValueYear = "0"; premiumValueMonth = "0"; } // Earnings if (data['earnings'] != null) { earningsToday = data['earnings']['today']?.toString() ?? "0"; earningsYear = data['earnings']['year']?.toString() ?? "0"; earningsMonth = data['earnings']['month']?.toString() ?? "0"; } else { earningsToday = "0"; earningsYear = "0"; earningsMonth = "0"; } // agents_performance if (data['agents_performance'] != null) { agentsPerformanceList = List>.from( (data['agents_performance'] as List).map( (item) => Map.from(item), ), ); agentsPerformanceList.sort((a, b) { // int aValue = a['total_policis_pending'] ?? 0; // int bValue = b['total_policis_pending'] ?? 0; int aValue = (a['total_policis_pending'] ?? 0) is int ? a['total_policis_pending'] : int.tryParse( a['total_policis_pending']?.toString() ?? '0', ) ?? 0; int bValue = (b['total_policis_pending'] ?? 0) is int ? b['total_policis_pending'] : int.tryParse( b['total_policis_pending']?.toString() ?? '0', ) ?? 0; return aValue.compareTo(bValue); // return aValue.compareTo(bValue); // ascending }); } //nonAgentsPerformanceList if (data['agents_performance'] != null) { nonAgentsPerformanceList = List>.from( (data['agents_performance'] as List).map( (item) => Map.from(item), ), ); // Sort descending nonAgentsPerformanceList.sort((a, b) { // int aValue = a['total_policy_pending'] ?? 0; // int bValue = b['total_policy_pending'] ?? 0; int aValue = (a['total_policis_pending'] ?? 0) is int ? a['total_policis_pending'] : int.tryParse( a['total_policis_pending']?.toString() ?? '0', ) ?? 0; int bValue = (b['total_policis_pending'] ?? 0) is int ? b['total_policis_pending'] : int.tryParse( b['total_policis_pending']?.toString() ?? '0', ) ?? 0; return bValue.compareTo(aValue); // descending }); } if (data['staff_level_pending_summary'] != null) { print('staff_level_pending_summary -'); staffQuotationsPendingList = List>.from( (data['staff_level_pending_summary'] as List).map( (item) => Map.from(item), ), ); print('staff_level_pending_summary - $staffQuotationsPendingList'); } if (data['quotations_pending'] != null) { quotationsPendingList = List>.from( (data['quotations_pending'] as List).map( (item) => Map.from(item), ), ); } if (data['quotations_approval_pending'] != null) { awaitingApprovalList = List>.from( (data['quotations_approval_pending'] as List).map( (item) => Map.from(item), ), ); } if (data['policies_pending'] != null) { policiesPendingList = List>.from( (data['policies_pending'] as List).map( (item) => Map.from(item), ), ); } if (data['unassigned_enquiry'] != null) { unAssignedEnqList = List>.from( (data['unassigned_enquiry'] as List).map( (item) => Map.from(item), ), ); } }); } else { getStaffData = []; originalData = []; } } catch (e) { print('Exception occurred: $e'); } finally { setState(() { isLoading = false; }); } } @override Widget build(BuildContext context) { final enquiries = ref.watch(enquiriesProvider); final managerId = ref.watch(managerIdProvider); final userId = ref.watch(userIdProvider); final role = ref.watch(userRoleProvider); return Column( children: [ ResponsiveBuilder.isMobile(context) ? Container( // color: Colors.redAccent, // height: MediaQuery.of(context).size.height, // ✅ take available space child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( color: Color(0XFFEDF6F5), borderRadius: const BorderRadius.only( topLeft: Radius.circular(50), // adjust radius topRight: Radius.circular(50), ), ), // 🔹 Tab Switcher child: Column( children: [ Container( decoration: BoxDecoration( color: const Color(0xFF425B5B), borderRadius: BorderRadius.circular(25), ), padding: const EdgeInsets.all(6), child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: [ Padding( padding: const EdgeInsets.all(8.0), child: buildTab("Awaiting Proposal", 0), ), const SizedBox(width: 10), Padding( padding: const EdgeInsets.all(8.0), child: buildTab("Awaiting Approval", 1), ), const SizedBox(width: 10), Padding( padding: const EdgeInsets.all(8.0), child: buildTab("Awaiting Policy", 2), ), ], ), ), ), const SizedBox(height: 20), // 🔹 Scrollable list ListView.builder( itemCount: currentList.length, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemBuilder: (context, index) { final item = currentList[index]; // Split date & time from created_on String date = ""; String time = ""; if ((item['created_on'] ?? "").isNotEmpty) { final parts = item['created_on'].split(' '); date = parts[0]; if (parts.isNotEmpty) { DateTime parsedDate = DateTime.parse( parts[0], ); date = DateFormat( 'dd-MM-yyyy', ).format(parsedDate); // 19/09/2025 } // time = parts.length > 1 ? parts[1] : ""; // Format the time part (HH:mm) if (parts.length >= 2) { final timeParts = parts[1].split(":"); time = "${timeParts[0]}:${timeParts[1]}"; // 05:45 } else { time = ""; } } return Card( elevation: 2, margin: const EdgeInsets.symmetric( vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), color: Colors.white, child: ListTile( onTap: () { dynamic id = item['id'].toString(); print("Tapped ID: ${item['id']}"); handleEdit(id); }, title: Text( item["reg_no"] ?? "-", // from API style: GoogleFonts.inter( fontWeight: FontWeight.bold, fontSize: 12, ), ), subtitle: (currentKey == 'policies') ? Text( item["insurer_name"] ?? "-", style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.bold, ), ) : SizedBox.shrink(), trailing: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( date, style: GoogleFonts.inter( fontSize: 12, ), ), Text(time, style: _tableDataTimeStyle), ], ), ), ); }, ), ], ), ), ], ), ), ) : Container( // color: Colors.red.shade100, // height: MediaQuery.of(context).size.height * 0.75, child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( children: [ // if (role != 'staff') if (role != 'staff' && role != 'handler' && role != 'manager') Row( children: [ Expanded( child: StatCard( title: "Policies Issued", today: policiesIssuedToday ?? '', month: policiesIssuedMonth ?? '', year: policiesIssuedYear ?? '', colorDark: Color(0xFF059669), imagePath: "assets/dashboard/Policy issue icon.png", ), ), SizedBox(width: 16), Expanded( child: StatCard( title: "Premium Value", today: premiumValueToday ?? '', month: premiumValueMonth ?? '', year: premiumValueYear ?? '', colorDark: Color(0XFF1d4ed8), // colorDark: Color(0xff2563eb), imagePath: "assets/dashboard/Premium value.png", ), ), SizedBox(width: 16), Expanded( child: StatCard( title: "Earnings", today: earningsToday ?? '', month: earningsMonth ?? '', year: earningsYear ?? '', colorDark: Color(0xff8b5cf6), imagePath: "assets/dashboard/Earnings.png", ), ), ], ), const SizedBox(height: 5), SizedBox( // ✅ replace Expanded height: (role == 'agent') ? MediaQuery.of(context).size.height * 0.69 //400 : (role == 'manager') ? MediaQuery.of(context).size.height * 0.8 : (role == 'staff' || role == 'handler') ? MediaQuery.of(context).size.height * 0.8 : MediaQuery.of(context).size.height * 0.5, // 350 adjust height as needed child: (role == 'manager' || role == 'handler') ? Row( children: [ Expanded( child: othersPendings( title: "Staff Wise Pending(${staffQuotationsPendingList.length})", data: staffQuotationsPendingList, stringFlag: "Proposal", role: role!, onRefresh: refresh, onExportExcel: getExportExcel, // onCallExport: getExportExcel2, ), ), // if (role == 'handler') ...[ Expanded( child: UnassignedEnq( key: UniqueKey(), title: "Unassigned Enquiries", role: role!, data: unAssignedEnqList, onRefresh: refresh, ), ), // ], ], ) : Row( children: [ Expanded( child: (role == 'agent') ? agentPendings( title: "Awaiting Proposal (${quotationsPendingList.length})", data: quotationsPendingList, role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ) : (role == 'manager') ? SizedBox.shrink() : agentPendings( title: "Awaiting Proposal (${quotationsPendingList.length})", data: quotationsPendingList, role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ), ), const SizedBox(width: 16), Expanded( child: (role == 'agent') ? agentPendings( title: "Awaiting Approval (${awaitingApprovalList.length})", data: awaitingApprovalList, role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ) : (role == 'manager') ? SizedBox.shrink() // othersPendings( // title: // "Awaiting Proposal (${quotationsPendingList.length})", // data: quotationsPendingList, // stringFlag: "Proposal", // ) : agentPendings( title: "Awaiting Approval (${awaitingApprovalList.length})", data: awaitingApprovalList, role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ), ), const SizedBox(width: 16), Expanded( child: (role == 'agent') ? agentPendings( title: "Awaiting Policy (${policiesPendingList.length})", data: policiesPendingList, stringFlag: "Policies", role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ) : (role == 'staff') ? // ? othersPendings( // title: // "Awaiting Proposal (${quotationsPendingList.length})", // data: quotationsPendingList, // stringFlag: "Proposal", // ) agentPendings( title: "Awaiting Policy (${policiesPendingList.length})", data: policiesPendingList, stringFlag: "Policies", role: role!, onEdit: (row) { handleEdit( row, ); // parent method is called }, onStaffEdit: (row, flag) { handleStaffEdit(row, flag); }, ) : SizedBox.shrink(), ), ], ), ), // const SizedBox(height: 5), // if (role == 'manager') // SizedBox( // // ✅ replace Expanded // height: 350, // adjust height as needed // child: Row( // children: [ // Expanded( // child: UnassignedEnq( // key: UniqueKey(), // title: "Unassigned Enquiries", // role: role!, // data: unAssignedEnqList, // onRefresh: refresh, // ), // ), // SizedBox(width: 16), // Expanded( // child: Performance( // title: "Performing Partner", // data: agentsPerformanceList, // ), // ), // SizedBox(width: 16), // Expanded( // child: Performance( // title: "Non-Performing Partner", // data: nonAgentsPerformanceList, // ), // ), // ], // ), // ), ], ), ), ), ], ); } // Widget buildTab(String title, int index) { // final isSelected = selectedIndex == index + 1; // return GestureDetector( // onTap: () { // print('buildTab - $index'); // // setState(() { // selectedIndex = index + 1; // print('buildTab1 - $selectedIndex'); // if (selectedIndex == 2) { // switcherStatus = 0; // } else { // switcherStatus = 1; // } // }); // }, // child: SizedBox( // child: Container( // padding: EdgeInsets.symmetric(vertical: 6, horizontal: 10), // decoration: BoxDecoration( // color: isSelected ? const Color(0xFFFFFFFF) : Colors.transparent, // borderRadius: BorderRadius.circular(16), // ), // child: Center( // child: Text( // title, // style: GoogleFonts.poppins( // fontSize: 12, // // color: isSelected ? Colors.black : Colors.white, // fontWeight: FontWeight.w500, // ), // maxLines: 2, // softWrap: true, // ), // ), // ), // ), // ); // } Widget buildTab(String title, int index) { final isSelected = selectedTabIndex == index; if (selectedTabIndex == 0) { currentList = quotationsPendingList; currentKey = 'pending'; } else if (selectedTabIndex == 1) { currentList = awaitingApprovalList; currentKey = 'approval'; } else if (selectedTabIndex == 2) { currentList = policiesPendingList; currentKey = 'policies'; } return GestureDetector( onTap: () { setState(() { selectedTabIndex = index; }); }, child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isSelected ? Colors.white : Colors.transparent, borderRadius: BorderRadius.circular(20), ), child: Text( title, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.bold, color: isSelected ? const Color(0xFF425B5B) : Colors.white, ), ), ), ); } } // Stats card widget class StatCard extends StatelessWidget { final String title; final String today; final String month; final String year; final String? imagePath; final Color? colorDark; const StatCard({ super.key, required this.title, required this.today, required this.month, required this.year, this.imagePath, this.colorDark, }); @override Widget build(BuildContext context) { return Card( color: Colors.white, // color: Color(0xFFF1F9F8), // color: Color(0xFFEAF6F4), elevation: 1, shadowColor: colorDark ?? null, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ Row( children: [ Container( padding: EdgeInsets.all(4.0), height: 28, width: 28, decoration: BoxDecoration( color: colorDark ?? Colors.grey, borderRadius: BorderRadius.circular(15), ), child: Image.asset( imagePath!, width: 18, height: 18, // color: colorDark ?? Colors.grey, color: Colors.white, ), ), const SizedBox(width: 8), Text( title, style: GoogleFonts.inter( fontSize: 12, fontWeight: FontWeight.w700, color: Color(0xFF425B5B), ), ), ], ), Divider(thickness: 0.1, color: colorDark ?? Colors.grey), const SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( today, textAlign: TextAlign.center, style: GoogleFonts.inter( fontWeight: FontWeight.bold, fontSize: 12, ), ), ), Expanded( child: Text( month, textAlign: TextAlign.center, style: GoogleFonts.inter( fontWeight: FontWeight.bold, fontSize: 12, ), ), ), Expanded( child: Text( year, textAlign: TextAlign.center, style: GoogleFonts.inter( fontWeight: FontWeight.bold, fontSize: 12, ), ), ), ], ), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( "Today", textAlign: TextAlign.center, style: topHeaderStyle, ), ), Expanded( child: Text( "This Month", textAlign: TextAlign.center, style: topHeaderStyle, ), ), Expanded( child: Text( "This Year", textAlign: TextAlign.center, style: topHeaderStyle, ), ), ], ), ], ), ), ); } } class agentPendings extends StatelessWidget { final String title; final String? stringFlag; String role; final List> data; // final Function(Map)? onEdit; final Function(String)? onEdit; // final Function(String)? onStaffEdit; final Function(String, String?)? onStaffEdit; agentPendings({ Key? key, required this.title, required this.data, this.stringFlag, required this.onStaffEdit, required this.role, required this.onEdit, }) : super(key: key); @override Widget build(BuildContext context) { print('-Data: $data'); return Card( color: Colors.white, // color: const Color(0xFFEAF6F4), elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text(title, style: _title), const SizedBox(height: 10), // Header row Container( padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), decoration: BoxDecoration( color: Color(0xFFE3F9F8), // color: const Color(0xFF3E5B56), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // flex: 1, // child: Text( // "S.No", // textAlign: TextAlign.center, // style: _headerStyle, // ), // ), Expanded( flex: 2, child: Text( "Date & Time", textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( flex: 2, child: Text( "Vehicle Number", textAlign: TextAlign.center, style: _headerStyle, ), ), if (stringFlag == "Policies") ...[ Expanded( flex: 2, child: Text( "Insurer", textAlign: TextAlign.center, style: _headerStyle, ), ), ], ], ), ), const SizedBox(height: 8), // List of rows Flexible( child: ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final row = data[index]; // Split date & time from created_on String date = ""; String time = ""; if ((row['created_on'] ?? "").isNotEmpty) { final parts = row['created_on'].split(' '); date = parts[0]; if (parts.isNotEmpty) { DateTime parsedDate = DateTime.parse(parts[0]); date = DateFormat( 'dd-MM-yyyy', ).format(parsedDate); // 19/09/2025 } // time = parts.length > 1 ? parts[1] : ""; // Format the time part (HH:mm) if (parts.length >= 2) { final timeParts = parts[1].split(":"); time = "${timeParts[0]}:${timeParts[1]}"; // 05:45 } else { time = ""; } } return InkWell( focusColor: Color(0xFF3E5B56), highlightColor: Color(0xFF3E5B56), borderRadius: BorderRadius.circular(2), onTap: (role == 'manager') ? null : (role == 'agent') ? () { print( "Clicked Partner role : $role - ${row['id']}", ); onEdit!(row['id'].toString()); // onEdit!(row['id']); } : () { print("Clicked Staff role : $role - ${row['id']}"); print("Clicked Staff stringFlag : $stringFlag"); onStaffEdit!(row['id'].toString(), stringFlag); }, child: Container( // margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.symmetric( vertical: 5, horizontal: 12, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(2), border: Border( bottom: BorderSide(color: Colors.blueGrey.shade50), ), ), child: Row( children: [ // Expanded( // flex: 1, // child: Text( // (index + 1).toString(), // textAlign: TextAlign.center, // style: _tableDataStyle, // ), // ), // Date & Time Expanded( flex: 2, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(date, style: _tableDataStyle), Text(time, style: _tableDataTimeStyle), ], ), ), // Registration number Expanded( flex: 2, child: Text( row['reg_no'] ?? "", textAlign: TextAlign.center, style: _tableDataStyle, ), ), if (stringFlag == "Policies") ...[ // Insurer company Expanded( flex: 2, child: Text( row['insurer_short_name'] ?? "", textAlign: TextAlign.center, style: _tableDataStyle, ), ), ], ], ), ), ); }, ), ), ], ), ), ); } } class othersPendings extends StatelessWidget { final String title; final String stringFlag; String role; final List> data; final VoidCallback? onRefresh; VoidCallback? onExportExcel; othersPendings({ Key? key, required this.title, required this.role, required this.data, required this.stringFlag, required this.onRefresh, this.onExportExcel, }) : super(key: key); @override Widget build(BuildContext context) { // ── Compute totals ────────────────────────────────────── int totalTodayAssigned = 0; int totalPending = 0; int totalInProgress = 0; int totalCompleted = 0; int totalPrevPending = 0; for (var row in data) { totalTodayAssigned += int.tryParse(row['today_assigned'] ?? '0') ?? 0; totalPending += int.tryParse(row['today_pending'] ?? '0') ?? 0; totalInProgress += int.tryParse(row['today_in_progress'] ?? '0') ?? 0; totalCompleted += int.tryParse(row['today_completed'] ?? '0') ?? 0; final rowPrevPending = (int.tryParse(row['total_pending'] ?? '0') ?? 0) - (int.tryParse(row['today_assigned'] ?? '0') ?? 0); totalPrevPending += rowPrevPending < 0 ? 0 : rowPrevPending; } return Card( color: Colors.white, elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // ── Title Row ─────────────────────────────────── Row( children: [ Text(title, style: _chartHeader), const Spacer(), InkWell( onTap: () => onRefresh?.call(), child: const Icon(Icons.refresh, size: 18), ), const SizedBox(width: 12), InkWell( onTap: () => onExportExcel?.call(), child: Tooltip( message: 'Export Excel', child: Container( padding: const EdgeInsets.all(5.0), decoration: BoxDecoration( color: const Color(0xFF2E7D6E), borderRadius: BorderRadius.circular(2.0), ), child: Image.asset( "assets/miscellaneous/export.png", height: 11, width: 11, ), ), ), ), ], ), const SizedBox(height: 10), // ── Header Row ────────────────────────────────── Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( color: const Color(0xFFE3F9F8), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ Expanded(flex: 2, child: Text("Staff Name", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text("Today Assigned", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text("Pending", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text("In Progress", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text("Completed", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text("Prev Pending", textAlign: TextAlign.center, style: _headerStyle)), ], ), ), const SizedBox(height: 6), // ── Data Rows ─────────────────────────────────── Flexible( child: ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final row = data[index]; final totalPendingVal = int.tryParse(row['total_pending']?.toString() ?? '0') ?? 0; final todayAssignedVal = int.tryParse(row['today_assigned']?.toString() ?? '0') ?? 0; final safePending = (totalPendingVal - todayAssignedVal).clamp(0, 99999); return _HoverableRow( onTap: () => handleDashboardNavigation( context, status: '', staffId: row['staff_id'] ?? '', role: role, ), child: Row( children: [ _dataCell(row['staff_name'] ?? '', flex: 2), _dataCell(row['today_assigned'] ?? '', flex: 2), _dataCell(row['today_pending'] ?? '', flex: 2), _dataCell(row['today_in_progress'] ?? '', flex: 2), _dataCell(row['today_completed'] ?? '', flex: 2), _dataCell(safePending.toString(), flex: 2), ], ), ); }, ), ), const SizedBox(height: 6), // ── Footer Total Row ──────────────────────────── Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( color: const Color(0xFFF1F5F9), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ Expanded(flex: 2, child: Text("Total", textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text(totalTodayAssigned.toString(), textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text(totalPending.toString(), textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text(totalInProgress.toString(), textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text(totalCompleted.toString(), textAlign: TextAlign.center, style: _headerStyle)), Expanded(flex: 2, child: Text(totalPrevPending.toString(), textAlign: TextAlign.center, style: _headerStyle)), ], ), ), ], ), ), ); } } class awaitingApproval extends StatelessWidget { final String title; final String stringFlag; final List> data; awaitingApproval({ Key? key, required this.title, required this.data, required this.stringFlag, }) : super(key: key); @override Widget build(BuildContext context) { print(' Data: $data'); return Card( color: Colors.white, // color: const Color(0xFFEAF6F4), elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text(title, style: _title), const SizedBox(height: 10), // Header row Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( // color: const Color(0xFF3E5B56), color: Color(0xFFE3F9F8), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // flex: 1, // child: Text( // "S.No", // textAlign: TextAlign.center, // style: _headerStyle, // ), // ), Expanded( flex: 2, child: Text( "Staff Name", textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( flex: 2, child: Text( // stringFlag + " Issued", 'Pending Count', textAlign: TextAlign.center, style: _headerStyle, ), ), // (stringFlag == "Policies") // ? Expanded( // flex: 2, // child: Text( // "Total Premium Value", // textAlign: TextAlign.center, // style: _headerStyle, // ), // ) // : const SizedBox.shrink(), ], ), ), const SizedBox(height: 8), // List of rows Flexible( child: ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final row = data[index]; final issuedCount = stringFlag == "Policies" ? (row['total_policis_pending'] ?? 0).toString() : (row['total_quotation_pending'] ?? 0).toString(); final permiumValue = row['total_premium_value'] == null ? '0' : row['total_premium_value']; return Container( margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.symmetric( vertical: 5, horizontal: 12, ), decoration: BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide( color: Colors.blueGrey.shade100, width: 0.3, ), ), // borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // flex: 1, // child: Text( // (index + 1).toString(), // textAlign: TextAlign.center, // style: _tableDataStyle, // ), // ), Expanded( flex: 2, child: Text( row['staff_name'] ?? "", textAlign: TextAlign.center, style: _tableDataStyle, ), ), Expanded( flex: 2, child: Text( // issuedCount, (row['total_approval_pending'] ?? 0).toString(), textAlign: TextAlign.center, style: _tableDataStyle, ), ), // stringFlag == "Policies" // ? Expanded( // flex: 2, // child: Text( // formatToCroresLakhsAndThousands(permiumValue), // textAlign: TextAlign.center, // style: GoogleFonts.inter( // fontSize: 14, // fontWeight: FontWeight.w500, // ), // ), // ) // : const SizedBox.shrink(), ], ), ); }, ), ), ], ), ), ); } } class Performance extends StatelessWidget { final String title; final List> data; Performance({Key? key, required this.title, required this.data}) : super(key: key); @override Widget build(BuildContext context) { return Card( // color: const Color(0xFFEAF6F4), color: Colors.white, elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text(title, style: _chartHeader), const SizedBox(height: 10), // Header row Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( color: Color(0xFFE3F9F8), // color: const Color(0xFF3E5B56), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // child: Text( // "S.No", // textAlign: TextAlign.center, // style: _headerStyle, // ), // ), Expanded( child: Text( "Partner Name", textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( child: Text( "Policies Issued", textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( child: Text( title == "Performing Partners" ? "Premium Value" : "Status", textAlign: TextAlign.center, style: _headerStyle, ), ), ], ), ), const SizedBox(height: 8), // List of rows Flexible( child: ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final row = data[index]; return Container( // height: 5200, margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.symmetric( vertical: 5, horizontal: 12, ), decoration: BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide( color: Colors.blueGrey.shade100, width: 0.3, ), ), // borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // child: Text( // (index + 1).toString(), // convert int to string // textAlign: TextAlign.center, // style: _tableDataStyle, // ), // ), // Expanded( // child: Text( // row['agent_name'] ?? "", // textAlign: TextAlign.center, // style: _tableDataStyle, // ), // ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // Top: Agent Name Text( row['agent_name'] ?? "", textAlign: TextAlign.center, style: _tableDataStyle, maxLines: 1, overflow: TextOverflow.ellipsis, ), // Bottom: Agent Code (light weight) Text( row['agent_code'] ?? "", textAlign: TextAlign.center, style: _tableDataTimeStyle.copyWith( fontWeight: FontWeight.w300, // lighter fontSize: 12, ), ), ], ), ), Expanded( child: Text( row['total_policy_issued'] ?? "", textAlign: TextAlign.center, style: _tableDataStyle, ), ), Expanded( child: Text( title == "Performing Partners" ? formatToCroresLakhsAndThousands( row['total_premium_value'] ?? 0, ) : (row['status']?.toString() ?? ""), textAlign: TextAlign.center, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w500, color: title == "Performing Partners" ? Colors.black : (row['status']?.toString().toLowerCase() == "active" ? Colors.green : Colors.red), ), ), ), ], ), ); }, ), ), ], ), ), ); } } class UnassignedEnq extends StatelessWidget { final String title; final List> data; final VoidCallback? onRefresh; String role; UnassignedEnq({ Key? key, required this.title, required this.data, this.onRefresh, required this.role, }) : super(key: key); @override Widget build(BuildContext context) { return SelectionArea( child: Card( color: Colors.white, // color: const Color(0xFFEAF6F4), elevation: 1, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Title Text(title, style: _chartHeader), const SizedBox(height: 10), // Header row Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12), decoration: BoxDecoration( // color: const Color(0xFF3E5B56), color: Color(0xFFE3F9F8), borderRadius: BorderRadius.circular(10), ), child: Row( children: [ // Expanded( // child: Text( // "S.No", // textAlign: TextAlign.center, // style: _headerStyle, // ), // ), Expanded( child: Text( "Date", // textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( child: Text( "Partner", // textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( child: Text( "Reg.No.", // textAlign: TextAlign.center, style: _headerStyle, ), ), Expanded( child: Text( "Insured Name", // textAlign: TextAlign.center, style: _headerStyle, ), ), ], ), ), const SizedBox(height: 8), // List of rows Flexible( child: ListView.builder( itemCount: data.length, itemBuilder: (context, index) { final row = data[index]; String date = ""; String time = ""; if ((row['created_on'] ?? "").isNotEmpty) { final parts = row['created_on'].split(' '); date = parts[0]; if (parts.isNotEmpty) { DateTime parsedDate = DateTime.parse(parts[0]); date = DateFormat( 'dd-MM-yyyy', ).format(parsedDate); // 19/09/2025 } // time = parts.length > 1 ? parts[1] : ""; // Format the time part (HH:mm) if (parts.length >= 2) { final timeParts = parts[1].split(":"); time = "${timeParts[0]}:${timeParts[1]}"; // 05:45 } else { time = ""; } } return InkWell( focusColor: Color(0xFF3E5B56), highlightColor: Color(0xFF3E5B56), borderRadius: BorderRadius.circular(2), // for ripple effect // onTap: () { // handleDashboardNavigation( // context, // status: "To be assigned", // staffId: row['staff_id'] ?? '', // role: role, // ); // }, onTap: () { // Print the id when row is clicked print("Clicked ID fd: ${row['id']}"); // You can also navigate or perform any action here showDialog( context: context, builder: (ctx) => AssignStaffDialog( enquiryPrimaryId: row['id'], regNum: row['reg_no'], userId: 1, onSubmit: (value) { debugPrint("New assignY: $value"); if (onRefresh != null) { onRefresh!(); // ✅ call the parent's refresh } }, ), ); }, child: Container( // height: 5200, margin: const EdgeInsets.symmetric(vertical: 5), padding: const EdgeInsets.symmetric( vertical: 5, horizontal: 12, ), decoration: BoxDecoration( color: Colors.white, border: Border( bottom: BorderSide( color: Colors.blueGrey.shade100, width: 0.3, ), ), // borderRadius: BorderRadius.circular(10), ), child: Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(date, style: _tableDataStyle), Text(time, style: _tableDataTimeStyle), ], ), ), // Expanded( // child: Text( // row['agent_name'] ?? '', // convert int to string // // textAlign: TextAlign.center, // style: _tableDataStyle, // ), // ), Expanded( child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.start, // align right children: [ // Top: Agent Name Text( row['agent_name'] ?? "", textAlign: TextAlign.left, style: _tableDataStyle, maxLines: 1, overflow: TextOverflow.ellipsis, ), // Bottom: Agent Code (light weight) Text( row['agent_code'] ?? "", textAlign: TextAlign.left, style: _tableDataTimeStyle, ), ], ), ), Expanded( child: Text( row['reg_no'] ?? "", style: _tableDataStyle, ), ), Expanded( child: Text( row['insured_name'] ?? "", style: _tableDataStyle, ), ), ], ), ), ); }, ), ), ], ), ), ) ); } } Future handleDashboardNavigation( BuildContext context, { required String status, String? staffId, required String role, }) async { print('Dashboard Tap => Status: $status | Staff: $staffId'); final prefs = await SharedPreferences.getInstance(); // ✅ Clear any old data await prefs.remove('dashboardKeyProvider'); await prefs.remove('dashboardStatusProvider'); await prefs.remove('dashboardStaffIdProvider'); // ✅ Save new values await prefs.setString('dashboardKeyProvider', 'fromDashboard'); await prefs.setString('dashboardStatusProvider', status); await prefs.setString('dashboardStaffIdProvider', staffId!); context.go( AppRoutes.enquiryForStaff, extra: { 'fromDashboard': true, }, ); // context.go(AppRoutes.enquiryForStaff); // // ✅ Navigate // if (role == 'manager') { // context.go(AppRoutes.enquiryForStaff); // } else { // context.go(AppRoutes.enquiryHandlerLst); // } } final _headerStyle = GoogleFonts.inter( fontWeight: FontWeight.w600, fontSize: 11.5, color: Colors.black, ); final _title = GoogleFonts.inter( fontWeight: FontWeight.bold, fontSize: 11.5, // color: Colors.red, color: const Color(0xff425B5B), ); final _tableDataStyle = GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w500, ); final _tableDataTimeStyle = GoogleFonts.inter( fontSize: 10, fontWeight: FontWeight.w400, ); final topHeaderStyle = GoogleFonts.inter( fontSize: 11, color: Colors.black, fontWeight: FontWeight.w500, ); final _chartHeader = GoogleFonts.poppins( fontSize: 11.5, color: Colors.black, fontWeight: FontWeight.w500, ); // ─── Helper Widgets ────────────────────────────────────────────────────────── Widget _dataCell(String text, {int flex = 2}) { return Expanded( flex: flex, child: Text( text, textAlign: TextAlign.center, style: GoogleFonts.inter( fontSize: 11, fontWeight: FontWeight.w500, color: const Color(0xFF2C3E3D), ), ), ); } // ─── Hoverable Row Widget ─────────────────────────────────────────────────── class _HoverableRow extends StatefulWidget { final Widget child; final VoidCallback onTap; const _HoverableRow({ required this.child, required this.onTap, }); @override State<_HoverableRow> createState() => _HoverableRowState(); } class _HoverableRowState extends State<_HoverableRow> { bool _isHovered = false; @override Widget build(BuildContext context) { return MouseRegion( onEnter: (_) => setState(() => _isHovered = true), onExit: (_) => setState(() => _isHovered = false), cursor: SystemMouseCursors.click, child: GestureDetector( onTap: widget.onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 180), curve: Curves.easeInOut, margin: const EdgeInsets.symmetric(vertical: 2, horizontal: 4), padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 12), decoration: BoxDecoration( color: _isHovered ? const Color(0xFFD4F3EF) : Colors.white, borderRadius: BorderRadius.circular(10), border: Border.all( color: _isHovered ? const Color(0xFF4ABFB5) : Colors.transparent, width: 1.2, ), boxShadow: _isHovered ? [ BoxShadow( color: const Color(0xFF4ABFB5).withOpacity(0.18), blurRadius: 8, offset: const Offset(0, 3), ), ] : [], ), child: widget.child, ), ), ); } }