FIX_BUG_Solved

This commit is contained in:
sanjeev.p 2026-03-11 12:17:08 +05:30
parent 50a1efb695
commit ae1abb3243
7 changed files with 573 additions and 664 deletions

File diff suppressed because one or more lines are too long

View File

@ -40,7 +40,7 @@ class ToastHelper {
showProgressBar: true,
closeButtonShowType: CloseButtonShowType.onHover,
closeOnClick: false,
pauseOnHover: true,
pauseOnHover: false,
dragToClose: true,
applyBlurEffect: true,
callbacks: ToastificationCallbacks(
@ -88,7 +88,7 @@ class ToastHelper {
showProgressBar: true,
closeButtonShowType: CloseButtonShowType.onHover,
closeOnClick: false,
pauseOnHover: true,
pauseOnHover: false,
dragToClose: true,
applyBlurEffect: true,
callbacks: ToastificationCallbacks(
@ -136,7 +136,7 @@ class ToastHelper {
showProgressBar: true,
closeButtonShowType: CloseButtonShowType.onHover,
closeOnClick: false,
pauseOnHover: true,
pauseOnHover: false,
dragToClose: true,
applyBlurEffect: true,
callbacks: ToastificationCallbacks(
@ -185,7 +185,7 @@ class ToastHelper {
showProgressBar: true,
closeButtonShowType: CloseButtonShowType.onHover,
closeOnClick: false,
pauseOnHover: true,
pauseOnHover: false,
dragToClose: true,
applyBlurEffect: true,
callbacks: ToastificationCallbacks(

View File

@ -237,6 +237,10 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
bool showExistingFile = false;
String? existingFileName;
bool showEndorsementExistingFile = false;
String? existingEndorsementFileName;
PlatformFile? docUploadedEndorsementEndorsFile;
@override
void initState() {
super.initState();
@ -248,6 +252,9 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
showExistingFile =
existingFileName != null && existingFileName.toString().isNotEmpty;
existingEndorsementFileName = widget.item?['endorsement_completion_file'];
showEndorsementExistingFile = existingEndorsementFileName != null && existingEndorsementFileName.toString().isNotEmpty;
// INITIALIZE CONTROLLERS MAP
controllers = {
'policyNum': TextEditingController(),
@ -664,6 +671,22 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
}
}
if (docUploadedEndorsementEndorsFile != null) {
try {
if (docUploadedEndorsementEndorsFile!.bytes != null) {
final multipartFile = http.MultipartFile.fromBytes(
'endorsement_completion_file', // Endorsement file field key
docUploadedEndorsementEndorsFile!.bytes!,
filename: docUploadedEndorsementEndorsFile!.name,
);
request.files.add(multipartFile);
}
print("📎 Endorsement file attached: ${docUploadedEndorsementEndorsFile!.name}");
} catch (e) {
print("❌ Failed to attach Endorsement file: $e");
}
}
print(" Sending request with fields: ${request.fields}");
try {
@ -702,6 +725,16 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
}
}
String get pdfDocumentTitle {
if (existingEndorsementFileName != null && existingEndorsementFileName!.isNotEmpty) {
return 'Endorsement Document';
} else if (existingFileName != null && existingFileName!.isNotEmpty) {
return 'Policy Document';
} else {
return 'Document';
}
}
// ================= UI =================
@override
@ -781,9 +814,9 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const Text(
'Original Endorsement Document',
style: TextStyle(
Text(
pdfDocumentTitle,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w500,
),
@ -1280,6 +1313,16 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(child: buildEndorsementUploadBox()),
const SizedBox(width: 25),
const Expanded(child: SizedBox()), // empty spacer
],
),
Divider(
color: Color(0xFFe5e7eb),
thickness: 1,
@ -1721,7 +1764,7 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
"Upload Document",
"Upload Policy Document",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
@ -1749,30 +1792,45 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
child: Row(
children: [
const Icon(Icons.insert_drive_file, color: Color(0xFF0F766E)),
const SizedBox(width: 12),
Expanded(
child: Text(
existingFileName!,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w400,
),
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w400),
),
),
/// DOWNLOAD BUTTON
Tooltip(
message: "Download",
child: GestureDetector(
onTap: () {
final id = widget.item?['id'];
apiService.downloadFile(
apiUrl: 'endorsement/downloadEndorsementCompletionFile?id=$id',
apiId: id,
localFile: null,
fileName: existingFileName!,
);
},
child: const Icon(Icons.download, color: Color(0xFF0F766E)),
),
),
const SizedBox(width: 8),
/// REMOVE BUTTON
GestureDetector(
onTap: () {
setState(() {
showExistingFile = false;
existingFileName = null;
docUploadedEndorsFile = null;
});
},
child: const Icon(Icons.close, color: Colors.red),
Tooltip(
message: "Remove",
child: GestureDetector(
onTap: () {
setState(() {
showExistingFile = false;
existingFileName = null;
docUploadedEndorsFile = null;
});
},
child: const Icon(Icons.close, color: Colors.red),
),
),
],
),
@ -1845,6 +1903,145 @@ class _endorsomentValidationState extends ConsumerState<endorsomentValidation> {
);
}
Widget buildEndorsementUploadBox() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// Label Row
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: const [
Text(
"Upload Endorsement Document",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Color(0xFF374151),
),
),
Text("PDF",style: TextStyle(fontSize: 10, color: Color(0xFF6B7280)),),
],
),
const SizedBox(height: 10),
/// 🔹 IF Endorsement EXISTING FILE (EDIT MODE)
if (showEndorsementExistingFile && existingEndorsementFileName != null)
Container(
height: 70,
padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: const Color(0xFF0F766E), width: 1.5),
),
child: Row(
children: [
const Icon(Icons.insert_drive_file, color: Color(0xFF0F766E)),
const SizedBox(width: 12),
Expanded(
child: Text(
existingEndorsementFileName!,
overflow: TextOverflow.ellipsis,
style: const TextStyle(fontSize: 13, fontWeight: FontWeight.w400),
),
),
/// DOWNLOAD BUTTON
Tooltip(
message: "Download",
child: GestureDetector(
onTap: () {
final id = widget.item?['id'];
apiService.downloadFile(
apiUrl: 'endorsement/downloadEndorsementCompletionFile?id=$id&type=completion',
apiId: id,
localFile: null,
fileName: existingEndorsementFileName!,
);
},
child: const Icon(Icons.download, color: Color(0xFF0F766E)),
),),
const SizedBox(width: 8),
/// REMOVE Endorsement BUTTON
Tooltip(
message: "Remove",
child: GestureDetector(
onTap: () {
setState(() {
showEndorsementExistingFile = false;
existingEndorsementFileName = null;
docUploadedEndorsementEndorsFile = null;
});
},
child: const Icon(Icons.close, color: Colors.red),
),),
],
),
)
/// 🔹 ELSE SHOW Endorsement UPLOAD BOX
else
GestureDetector(
onTap: () async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
type: FileType.custom,
allowedExtensions: ['pdf'],
);
if (result != null) {
setState(() {
docUploadedEndorsementEndorsFile = result.files.first;
});
}
},
child: Container(
height: 160,
decoration: BoxDecoration(
color: const Color(0xFFF8FAFC),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: const Color(0xFF0F766E), width: 1.5),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(
Icons.attach_file,
size: 34,
color: Color(0xFF9CA3AF),
),
const SizedBox(height: 12),
Text(
docUploadedEndorsementEndorsFile != null
? docUploadedEndorsementEndorsFile!.name
: "Click to upload or drag & drop",
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w400,
color: Color(0xFF374151),
),
),
const SizedBox(height: 6),
const Text(
"Endorsement document, endorsement copy",
style: TextStyle(fontSize: 11, color: Color(0xFF6B7280)),
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
buildFileChip("PDF"),
const SizedBox(width: 8),
buildFileChip("Max 5MB"),
],
),
],
),
),
),
],
);
}
// Widget buildUploadBox() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -2210,7 +2210,7 @@ class endosementState extends ConsumerState<Endorsement> {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text('Upload Endorsement PDF', style: _dataBold),
Text('Upload Revised Endorsement Document (PDF)', style: _dataBold),
const SizedBox(height: 10),
_buildEndorsementUploadField(item),
],
@ -2233,12 +2233,12 @@ class endosementState extends ConsumerState<Endorsement> {
mainAxisSize: MainAxisSize.min,
children: [
// UPLOAD LABEL
Text('Upload', style: GoogleFonts.poppins(fontSize: 11, fontWeight: FontWeight.w500)),
Text('Upload Revised Document', style: GoogleFonts.poppins(fontSize: 11, fontWeight: FontWeight.w500)),
const SizedBox(height: 6),
// UPLOAD FIELD
ThemedUploadField(
hintText: selectedFileNames ?? "Upload Document",
hintText: selectedFileNames ?? "Upload Revised Document",
padHorizontal: 4,
padVertical: 5,
fontSZ: 11,

View File

@ -1212,7 +1212,6 @@ class othersPendings extends StatelessWidget {
final List<Map<String, dynamic>> data;
final VoidCallback? onRefresh;
VoidCallback? onExportExcel;
// final Future<void> Function(String status, String staffId)? onCallExport;
othersPendings({
Key? key,
@ -1222,50 +1221,31 @@ class othersPendings extends StatelessWidget {
required this.stringFlag,
required this.onRefresh,
this.onExportExcel,
// this.onCallExport,
}) : super(key: key);
@override
Widget build(BuildContext context) {
print(' Data: $data');
// Compute totals
// Compute totals
int totalTodayAssigned = 0;
int totalPending = 0;
int totalInProgress = 0;
int totalCompleted = 0;
int totalPrevPending = 0;
int totalPendingAll = 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;
totalPrevPending += int.tryParse(row['total_completed'] ?? '0') ?? 0;
int totalPendingdata =
int.tryParse(row['total_pending']?.toString() ?? '0') ?? 0;
int todayAssigned =
int.tryParse(row['today_assigned']?.toString() ?? '0') ?? 0;
// totalTodayAssigned += todayAssigned;
totalPendingAll += totalPendingdata;
int staffPending = totalPendingdata - todayAssigned;
// totalPrevPending += staffPending;
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);
(int.tryParse(row['today_assigned'] ?? '0') ?? 0);
totalPrevPending += rowPrevPending < 0 ? 0 : rowPrevPending;
}
return Card(
color: Colors.white,
// color: const Color(0xFFEAF6F4),
elevation: 1,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
child: Padding(
@ -1273,470 +1253,115 @@ class othersPendings extends StatelessWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Title
// Title Row
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(title, style: _chartHeader),
Spacer(),
const Spacer(),
InkWell(
onTap: () {
onRefresh!();
},
child: Icon(Icons.refresh, size: 18),
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,
),
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
// Header Row
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: Color(0xFFE3F9F8),
// color: const Color(0xFF3E5B56),
color: const Color(0xFFE3F9F8),
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: [
// Expanded(
// flex: 1,
// child: Text(
// "S.No",
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// ),
// if (role == 'manager') ...[
// Expanded(
// flex: 2,
// child: Text(
// "Handler Name",
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// ),
// ],
Expanded(
flex: 2,
child: Text(
"Staff Name",
textAlign: TextAlign.center,
style: _headerStyle,
),
),
// Expanded(
// flex: 2,
// child: Text(
// // stringFlag + " Issued",
// 'Total Assigned',
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// ),
// Expanded(
// flex: 2,
// child: Text(
// 'To be assigned',
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// ),
// Expanded(
// flex: 2,
// child: Text(
// 'Total Assigned',
// 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,
),
),
// Expanded(
// flex: 2,
// child: Text(
// // stringFlag + " Issued",
// 'Policy Created',
// textAlign: TextAlign.center,
// style: _headerStyle,
// ),
// ),
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: 8),
const SizedBox(height: 6),
// List of rows
// Data Rows
Flexible(
child: ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
final row = data[index];
final totalPending =
int.tryParse(row['total_pending']?.toString() ?? '0') ??
0;
final todayAssigned =
int.tryParse(row['today_assigned']?.toString() ?? '0') ??
0;
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);
final staffPending = (totalPending - todayAssigned);
final safePending = staffPending < 0 ? 0 : staffPending;
// final staffPending = totalPending - todayAssigned;
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: 3),
padding: const EdgeInsets.symmetric(
vertical: 4,
horizontal: 12,
),
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: Colors.blueGrey.shade100,
width: 0.3,
),
),
// borderRadius: BorderRadius.circular(10),
return _HoverableRow(
onTap: () => handleDashboardNavigation(
context,
status: '',
staffId: row['staff_id'] ?? '',
role: role,
),
child: Row(
children: [
Expanded(
flex: 2,
child: Text(
row['staff_name'] ?? "",
textAlign: TextAlign.left,
// textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
Expanded(
flex: 2,
child: Material(
color: Colors.white,
child: Center(
child: InkWell(
hoverColor: Color(0xFFEAF6F4),
onTap: () async {
print(
'total_assigned_today : ${row['total_assigned']}',
);
handleDashboardNavigation(
context,
status: '',
// status: "Assigned",
staffId: row['staff_id'] ?? '',
role: role,
);
// if (onCallExport != null) {
// await onCallExport!(
// "TodayAssigned",
// row['staff_id'].toString(),
// );
// }
},
child: Text(
row['today_assigned'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
),
),
),
Expanded(
flex: 2,
child: Material(
color: Colors.white,
child: Center(
child: InkWell(
hoverColor: Color(0xFFEAF6F4),
onTap: () async {
print(
'total_assigned : ${row['total_assigned']}',
);
handleDashboardNavigation(
context,
status: "Assigned",
staffId: row['staff_id'] ?? '',
role: role,
);
// if (onCallExport != null) {
// await onCallExport!(
// "Assigned",
// row['staff_id'].toString(),
// );
// }
},
child: Text(
row['today_pending'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
),
),
),
Expanded(
flex: 2,
child: Material(
color: Colors.white,
child: Center(
child: InkWell(
// hoverColor: Color(0xFFEAF6F4),
onTap: () async {
print(
'Awaiting Proposal : ${row['total_in_progress']}',
);
handleDashboardNavigation(
context,
status: "In progress",
staffId: row['staff_id'] ?? '',
role: role,
);
// if (onCallExport != null) {
// await onCallExport!(
// 'InProgress',
// row['staff_id'].toString(),
// );
// }
},
child: Text(
row['today_in_progress'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
),
),
),
Expanded(
flex: 2,
child: Material(
color: Colors.white,
child: Center(
child: InkWell(
hoverColor: Color(0xFFEAF6F4),
onTap: () async {
print(
'Awaiting Approval : ${row['total_completed']} - ${row['staff_id']}',
);
handleDashboardNavigation(
context,
status: "Completed",
staffId: row['staff_id'] ?? '',
role: role,
);
// if (onCallExport != null) {
// await onCallExport!(
// 'Completed',
// row['staff_id'].toString(),
// );
// }
},
child: Text(
row['today_completed'] ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
),
),
),
Expanded(
flex: 2,
child: Material(
color: Colors.white,
child: Center(
child: InkWell(
hoverColor: Color(0xFFEAF6F4),
onTap: () async {
print(
'Awaiting Approval : ${row['total_completed']} - ${row['staff_id']}',
);
handleDashboardNavigation(
context,
status: 'PrevPending',
staffId: row['staff_id'] ?? '',
role: role,
);
// 2. Call the Export function
// We use await here so the 'isLoading' state is respected
// and errors are caught properly.
// if (onCallExport != null) {
// await onCallExport!(
// 'PrevPending',
// row['staff_id'].toString(),
// );
// }
},
child: Text(
safePending.toString() ?? "",
// row['total_approval_pending'] ?? "",
textAlign: TextAlign.center,
style: _tableDataStyle,
),
),
),
),
),
// Expanded(
// flex: 2,
// child: Text(
// row['policy_created'] ?? "",
// // row['total_approval_pending'] ?? "",
// textAlign: TextAlign.center,
// style: _tableDataStyle,
// ),
// ),
_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: 8),
// Header row
const SizedBox(height: 6),
// Footer Total Row
Container(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
decoration: BoxDecoration(
color: Color(0xFFF1F5F9),
// color: Color(0xFFE3F9F8),
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,
),
),
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)),
],
),
),
],
),
),
@ -2383,3 +2008,74 @@ final _chartHeader = GoogleFonts.poppins(
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,
),
),
);
}
}

View File

@ -298,23 +298,53 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
print('dashboardStatus - $dashboardStatus');
print('dashboardStaffId - $dashboardStaffId');
if (managerId != null &&
dashboardKey != null &&
dashboardStatus != null &&
dashboardStaffId != null) {
print("DASHBOARD STATus-$dashboardStatus -- $dashboardStaffId -");
SelectedStatus = dashboardStatus;
SelectedStaffId = dashboardStaffId;
getStaffList(
managerId,
roleId,
SelectedStatus: dashboardStatus,
SelectedStaffId: dashboardStaffId,
);
} else {
print('ELSE');
getStaffList(managerId, roleId);
}
// if (managerId != null &&
// dashboardKey != null &&
// dashboardStatus != null &&
// dashboardStaffId != null) {
// print("DASHBOARD STATus-$dashboardStatus -- $dashboardStaffId -");
// SelectedStatus = dashboardStatus;
// SelectedStaffId = dashboardStaffId;
// getStaffList(
// managerId,
// roleId,
// SelectedStatus: dashboardStatus,
// SelectedStaffId: dashboardStaffId,
// );
// } else {
// print('ELSE');
// getStaffList(managerId, roleId);
// }
// AFTER clear dashboardKey from prefs immediately after reading it:
if (managerId != null &&
dashboardKey != null &&
dashboardStatus != null &&
dashboardStaffId != null) {
print("DASHBOARD STATus-$dashboardStatus -- $dashboardStaffId -");
SelectedStatus = dashboardStatus;
SelectedStaffId = dashboardStaffId;
// FIX: Clear dashboard keys from SharedPreferences RIGHT NOW
// so that auto-refresh (30s timer) never re-applies dashboard dates
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
getStaffList(
managerId,
roleId,
SelectedStatus: dashboardStatus,
SelectedStaffId: dashboardStaffId,
);
// FIX: After first load, clear dashboardKey in memory too
// so getStaffList's date logic uses normal path on next call
dashboardKey = null;
} else {
print('ELSE');
getStaffList(managerId, roleId);
}
ref.listen(enquiryRefreshProvider, (prev, next) {
print('quickQuotationKey1');
@ -519,24 +549,27 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
Future<void> autoRefrshfilterDateRange() async {
print('autorefrshfilterDateRange');
// setState(() async {
final prefs = await SharedPreferences.getInstance();
// _formKey.currentState?.reset();
// FIX: Always clear dashboard keys before auto-refresh
// This is a safety net ensures stale dashboardKey never leaks into timer calls
if (dashboardKey == 'fromDashboard') {
dashboardKey = null;
_dashboardInitHandled = false;
await prefs.remove('dashboardKeyProvider');
await prefs.remove('dashboardStatusProvider');
await prefs.remove('dashboardStaffIdProvider');
}
final int parsedManagerId = int.tryParse(managerId.toString()) ?? 0;
print('autorefrshfilterDateRange 1');
getStaffList(
// managerId,
parsedManagerId,
roleId,
SelectedStatus: SelectedStatus ?? '',
SelectedStaffId: SelectedStaffId ?? '',
);
autoRefreshIndex = selectedIndex;
print('autoRefreshIndex - $autoRefreshIndex');
_searchStaffController.clear();
print('refrshfilterDateRange 2');
}
Future<void> refrshfilterDateRange() async {
@ -674,196 +707,179 @@ class EnquiryStaffState extends ConsumerState<EnquiryListStaffInline> {
}
Future<void> getStaffList(int managerId,
role, {
String fromDate = '',
String toDate = '',
String SelectedStatus = '',
String SelectedStaffId = '',
}) async {
print('A613 => Fns called => $managerId | $role');
role, {
String fromDate = '',
String toDate = '',
String SelectedStatus = '',
String SelectedStaffId = '',
}) async {
print('A613 => Fns called => $managerId | $role');
setState(() {
isLoadingStaffList = true;
});
print('A713 => Fns called => $managerId | $role');
dynamic fromDt;
dynamic toDt;
final fromDateVal = controllers['startDate']?.text ?? '';
final toDateVal = controllers['endDate']?.text ?? '';
final dateFormat = DateFormat('dd-MM-yyyy');
if (dashboardKey == 'fromDashboard' && SelectedStatus == "PrevPending") {
setState(() {
isLoadingStaffList = true;
_dashboardInitHandled = true;
});
print('A713 => Fns called => $managerId | $role');
final today = DateTime.now();
final DateTime yesterday = today.subtract(const Duration(days: 1));
final DateTime fromDate = DateTime(2025, 10, 1);
controllers['startDate']?.text = dateFormat.format(fromDate);
controllers['endDate']?.text = dateFormat.format(yesterday);
print('UnA813 => Fns called => $managerId | $role');
dynamic fromDt;
dynamic toDt;
fromDt = _dashboardInitHandled ? controllers['startDate']?.text : '';
toDt = _dashboardInitHandled ? controllers['endDate']?.text : '';
final fromDateVal = controllers['startDate']?.text ?? '';
final toDateVal = controllers['endDate']?.text ?? '';
print('PrevPending FROM TO - $fromDt - $toDt');
} else if (dashboardKey == 'fromDashboard' &&
SelectedStatus != "PrevPending" &&
SelectedStatus != '') {
final today = DateTime.now();
print('A913 => Fns called => $managerId | $role');
final dateFormat = DateFormat('dd-MM-yyyy');
if (dashboardKey == 'fromDashboard' && SelectedStatus == "PrevPending") {
setState(() {
_dashboardInitHandled = true;
});
final today = DateTime.now();
final DateTime yesterday = today.subtract(const Duration(days: 1));
final DateTime fromDate = DateTime(2025, 10, 1); // hardcoded Date
controllers['startDate']?.text = dateFormat.format(fromDate);
controllers['endDate']?.text = dateFormat.format(yesterday);
print('UnA813 => Fns called => $managerId | $role');
fromDt = _dashboardInitHandled ? controllers['startDate']?.text : '';
toDt = _dashboardInitHandled ? controllers['endDate']?.text : '';
print('End Date: ${controllers['endDate']?.text}');
print('STT Date: ${controllers['startDate']?.text}');
// For PREV PENDING set date range until yesterday
// Change to dd-MM-yyyy
// final dateFormat = DateFormat('dd-MM-yyyy');
// final yesterday = today.subtract(Duration(days: 1));
print('PrevPending FROM TO - $fromDt - $toDt');
} else if (dashboardKey != 'fromDashboard' &&
fromDateVal == '' &&
toDateVal == '') {
print("ENQ LIST PAGE");
print('A1013 => Fns called => $managerId | $role');
fromDt = _dashboardInitHandled ? controllers['startDate']?.text : '';
toDt = _dashboardInitHandled ? controllers['endDate']?.text : '';
// fromDt = dateFormat.format(yesterday.subtract(Duration(days: 15)));
// toDt = dateFormat.format(yesterday);
final today = DateTime.now();
fromDt = dateFormat.format(today.subtract(Duration(days: 4)));
toDt = dateFormat.format(today);
print('PrevPending FROM TO - $fromDt - $toDt');
} else if (dashboardKey == 'fromDashboard' &&
SelectedStatus != "PrevPending" &&
SelectedStatus != '') {
// For PREV PENDING set date range until yesterday
final today = DateTime.now();
print('A913 => Fns called => $managerId | $role');
// Change to dd-MM-yyyy
print('Enq FROM TO - $fromDt - $toDt');
} else {
print('A1113 => Fns called => $managerId | $role');
print('Pre Date its User Choosen Enq Inline list - $fromDt - $toDt');
if (_resetKeyEnable) {
print('A12131 => Fns called => $managerId | $role');
final dateFormat = DateFormat('dd-MM-yyyy');
// fromDt = dateFormat.format(today);
// toDt = dateFormat.format(today);
fromDt = _dashboardInitHandled ? controllers['startDate']?.text : '';
toDt = _dashboardInitHandled ? controllers['endDate']?.text : '';
print('End Date: ${controllers['endDate']?.text}');
print('STT Date: ${controllers['startDate']?.text}');
print('PrevPending FROM TO - $fromDt - $toDt');
} else if (dashboardKey != 'fromDashboard' &&
fromDateVal == '' &&
toDateVal == '') {
print("ENQ LIST PAGE");
print('A1013 => Fns called => $managerId | $role');
final today = DateTime.now();
fromDt = dateFormat.format(today.subtract(Duration(days: 4)));
// fromDt = dateFormat.format(today);
fromDt = dateFormat.format(today.subtract(const Duration(days: 4)));
toDt = dateFormat.format(today);
print('Enq FROM TO - $fromDt - $toDt');
} else {
print('A1113 => Fns called => $managerId | $role');
print('Pre Date its User Choosen Enq Inline list - $fromDt - $toDt');
if (_resetKeyEnable) {
print('A12131 => Fns called => $managerId | $role');
final dateFormat = DateFormat('dd-MM-yyyy');
final today = DateTime.now();
// final yesterday = today.subtract(Duration(days: 1));
// fromDt = dateFormat.format(yesterday.subtract(Duration(days: 15))); // Dont Delete any doubt Ref Suren
fromDt = dateFormat.format(today.subtract(const Duration(days: 4)));
toDt = dateFormat.format(today);
setState(() {
controllers['startDate']?.text = fromDt;
controllers['endDate']?.text = toDt;
_resetKeyEnable = false; // ask suren Never forgot
});
} else {
print('A13131 => Fns called => $managerId | $role');
fromDt = fromDateVal;
toDt = toDateVal;
}
}
print('Enq 2- $fromDt - $toDt');
String finalStatus = SelectedStatus;
print('finalStatus1 - $finalStatus');
print('A1213 => Fns called => $managerId | $role');
try {
final response = await apiService.fetchEnquiryList(
managerId,
userId,
role,
fromDate: _dashboardInitHandled
? controllers['startDate']?.text
: fromDt,
toDate: _dashboardInitHandled ? controllers['endDate']?.text : toDt,
// selectedStatus: (finalStatus != '' && finalStatus != 'PrevPending')
// ? finalStatus
// : '',
selectedStatus:
(SelectedStatus != '' && SelectedStatus != 'PrevPending')
? SelectedStatus
: '',
selectedStaffId: SelectedStaffId ?? '',
);
if (response['status'] == 'success') {
final data = response['data'];
final fromDate = response['from_date'] ?? '';
final toDate = response['to_date'] ?? '';
print('FromDate : $fromDate');
print('ToDate : $toDate');
print('A1213 => Fns called => $managerId | $role');
setState(() {
_resetKeyEnable = false;
controllers['startDate']?.text = fromDate;
controllers['endDate']?.text = toDate;
if (data is List) {
getStaffData = List<Map<String, dynamic>>.from(data);
originalData = List<Map<String, dynamic>>.from(data);
// Split data immediately after fetching
inProgressData = originalData
.where((item) => item['enquiry_status'] != 'Completed')
.toList();
print('inProgressData - $inProgressData');
completedData = originalData
.where((item) => item['enquiry_status'] == 'Completed')
.toList();
print('completedData - $completedData');
// filteredData now holds the currently displayed tab's data (without search)
// filteredData = (selectedIndex == 0)
// ? inProgressData
// : completedData;
// 👇 IMPORTANT: Set filteredData based on current tab
filteredData = (selectedIndex == 0)
? List.from(inProgressData)
: List.from(completedData);
if (SelectedStatus == 'Completed') {
selectedIndex = 1;
}
print('filteredData count: ${filteredData.length}');
print('inProgressData count: ${inProgressData.length}');
print('completedData count: ${completedData.length}');
} else if (data is Map) {
getStaffData = [Map<String, dynamic>.from(data)];
} else {
getStaffData = [];
}
originalData = getStaffData;
filteredData = List.from(originalData);
});
} else {
getStaffData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoadingStaffList = false;
controllers['startDate']?.text = fromDt;
controllers['endDate']?.text = toDt;
_resetKeyEnable = false;
});
} else {
print('A13131 => Fns called => $managerId | $role');
fromDt = fromDateVal;
toDt = toDateVal;
}
}
print('Enq 2- $fromDt - $toDt');
String finalStatus = SelectedStatus;
print('finalStatus1 - $finalStatus');
print('A1213 => Fns called => $managerId | $role');
try {
final response = await apiService.fetchEnquiryList(
managerId,
userId,
role,
fromDate: _dashboardInitHandled
? controllers['startDate']?.text
: fromDt,
toDate: _dashboardInitHandled ? controllers['endDate']?.text : toDt,
selectedStatus:
(SelectedStatus != '' && SelectedStatus != 'PrevPending')
? SelectedStatus
: '',
selectedStaffId: SelectedStaffId ?? '',
);
if (response['status'] == 'success') {
final data = response['data'];
final fromDate = response['from_date'] ?? '';
final toDate = response['to_date'] ?? '';
print('FromDate : $fromDate');
print('ToDate : $toDate');
print('A1213 => Fns called => $managerId | $role');
setState(() {
_resetKeyEnable = false;
controllers['startDate']?.text = fromDate;
controllers['endDate']?.text = toDate;
if (data is List) {
getStaffData = List<Map<String, dynamic>>.from(data);
originalData = List<Map<String, dynamic>>.from(data);
inProgressData = originalData
.where((item) => item['enquiry_status'] != 'Completed')
.toList();
print('inProgressData - $inProgressData');
completedData = originalData
.where((item) => item['enquiry_status'] == 'Completed')
.toList();
print('completedData - $completedData');
filteredData = (selectedIndex == 0)
? List.from(inProgressData)
: List.from(completedData);
if (SelectedStatus == 'Completed') {
selectedIndex = 1;
}
print('filteredData count: ${filteredData.length}');
print('inProgressData count: ${inProgressData.length}');
print('completedData count: ${completedData.length}');
} else if (data is Map) {
getStaffData = [Map<String, dynamic>.from(data)];
} else {
getStaffData = [];
}
originalData = getStaffData;
filteredData = List.from(originalData);
});
// FIX CHANGE 2: Clear dashboardKey AFTER first successful load
// so all subsequent auto-refresh timer calls (every 30s) use
// normal date logic instead of re-applying dashboard dates
if (dashboardKey == 'fromDashboard') {
dashboardKey = null;
_dashboardInitHandled = false;
print('✅ dashboardKey cleared after first successful load');
}
} else {
getStaffData = [];
originalData = [];
}
} catch (e) {
print('Exception occurred: $e');
} finally {
setState(() {
isLoadingStaffList = false;
});
}
}
String safeString(dynamic value) {
if (value == null) return '';

View File

@ -15,8 +15,8 @@
the `--base-href` argument provided to `flutter build`.
-->
<!-- <base href="$FLUTTER_BASE_HREF"> -->
<base href="/partner/"> <!-- Live build: also check env.dart (line 8) -->
<!-- <base href="/nhance/partner/app/"> &lt;!&ndash; Testing build: also check env.dart (line 9) &ndash;&gt;-->
<!-- <base href="/partner/"> Live build: also check env.dart (line 8) -->
<base href="/nhance/partner/app/"> <!-- Testing build: also check env.dart (line 9) -->
<!-- <base href="{Env.baseHref}">-->
<meta charset="UTF-8">