2081 lines
78 KiB
Dart
2081 lines
78 KiB
Dart
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<List<Map<String, String>>>((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<LiveDashboard> createState() => _DashboardState();
|
|
}
|
|
|
|
class _DashboardState extends ConsumerState<LiveDashboard> {
|
|
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<Map<String, dynamic>> dataVal = [];
|
|
List<Map<String, dynamic>> getStaffData = [];
|
|
List<Map<String, dynamic>> originalData = [];
|
|
List<Map<String, dynamic>> filteredData = [];
|
|
int selectedTabIndex = 0;
|
|
List<Map<String, dynamic>> currentList = [];
|
|
|
|
List<Map<String, dynamic>> staffQuotationsPendingList = []; // cross verify
|
|
List<Map<String, dynamic>> quotationsPendingList = []; // cross verify
|
|
List<Map<String, dynamic>> policiesPendingList = []; // cross verify
|
|
List<Map<String, dynamic>> awaitingApprovalList = []; // cross verify
|
|
List<Map<String, dynamic>> unAssignedEnqList = []; // cross verify
|
|
List<Map<String, dynamic>> agentsPerformanceList = []; // cross verify
|
|
List<Map<String, dynamic>> 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<void> 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<void> 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<void> 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<void> 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<void> 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<Map<String, dynamic>>.from(
|
|
(data['agents_performance'] as List).map(
|
|
(item) => Map<String, dynamic>.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<Map<String, dynamic>>.from(
|
|
(data['agents_performance'] as List).map(
|
|
(item) => Map<String, dynamic>.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<Map<String, dynamic>>.from(
|
|
(data['staff_level_pending_summary'] as List).map(
|
|
(item) => Map<String, dynamic>.from(item),
|
|
),
|
|
);
|
|
print('staff_level_pending_summary - $staffQuotationsPendingList');
|
|
}
|
|
|
|
if (data['quotations_pending'] != null) {
|
|
quotationsPendingList = List<Map<String, dynamic>>.from(
|
|
(data['quotations_pending'] as List).map(
|
|
(item) => Map<String, dynamic>.from(item),
|
|
),
|
|
);
|
|
}
|
|
|
|
if (data['quotations_approval_pending'] != null) {
|
|
awaitingApprovalList = List<Map<String, dynamic>>.from(
|
|
(data['quotations_approval_pending'] as List).map(
|
|
(item) => Map<String, dynamic>.from(item),
|
|
),
|
|
);
|
|
}
|
|
if (data['policies_pending'] != null) {
|
|
policiesPendingList = List<Map<String, dynamic>>.from(
|
|
(data['policies_pending'] as List).map(
|
|
(item) => Map<String, dynamic>.from(item),
|
|
),
|
|
);
|
|
}
|
|
|
|
if (data['unassigned_enquiry'] != null) {
|
|
unAssignedEnqList = List<Map<String, dynamic>>.from(
|
|
(data['unassigned_enquiry'] as List).map(
|
|
(item) => Map<String, dynamic>.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<Map<String, dynamic>> data;
|
|
|
|
// final Function(Map<String, dynamic>)? 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<Map<String, dynamic>> 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<Map<String, dynamic>> 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<Map<String, dynamic>> 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<Map<String, dynamic>> 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<void> 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,
|
|
),
|
|
),
|
|
);
|
|
}
|
|
} |