This commit is contained in:
Surendiran 2026-06-12 14:20:36 +05:30
parent c6b15a050a
commit 197a699c16

View File

@ -4,6 +4,7 @@ import 'package:csv/csv.dart';
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
@ -51,6 +52,9 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
String? _postPreToken = '';
TextEditingController searchController = TextEditingController();
TextEditingController searchClaimsStatusController = TextEditingController();
final ScrollController _statusScrollController = ScrollController();
bool _canScrollStatusLeft = false;
bool _canScrollStatusRight = false;
Map<String, TextEditingController> controllers = {};
List<dynamic> reversedDataPolicy = [];
@ -77,25 +81,33 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
int? appliedClaimStatus;
Color getStatusColor(String status) {
switch (status.toLowerCase()) {
case 'claim received':
return const Color(0xFF4A90E2); // blue
case 'under process':
return const Color(0xFFF5A623); // orange
case 'information required':
return const Color(0xFFFF8C42); // amber
case 'approved':
return const Color(0xFF2ECC71); // green
case 'settled':
return const Color(0xFF1ABC9C); // teal-green
case 'rejected':
return const Color(0xFFE74C3C); // red
case 'denial review awaite':
return const Color(0xFF9B59B6); // purple
case 'closed':
return const Color(0xFFB0BEC5); // purple
switch (status.toLowerCase().trim()) {
case 'claim intimation received':
return const Color(0xFF4A90E2);
case 'claim intimated':
return const Color(0xFF5B9BD5);
case 'insurer pending':
return const Color(0xFFF5A623);
case 'surveyor pending':
return const Color(0xFFFF8C42);
case 'insured pending':
return const Color(0xFFE67E22);
case 'insurer / surveyor pending':
return const Color(0xFFD35400);
case 'workshop pending':
return const Color(0xFF9B59B6);
case 'claim approved':
return const Color(0xFF2ECC71);
case 'claim settled':
return const Color(0xFF1ABC9C);
case 'claim closed':
return const Color(0xFF95A5A6);
case 'claim rejected':
return const Color(0xFFE74C3C);
case 'claim withdrawn':
return const Color(0xFF7F8C8D);
default:
return const Color(0xFFB0BEC5); // grey fallback
return const Color(0xFFB0BEC5);
}
}
@ -125,6 +137,9 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
for (String field in tabHeader) {
controllers[field] = TextEditingController();
}
_statusScrollController.addListener(_updateStatusScrollArrows);
WidgetsBinding.instance
.addPostFrameCallback((_) => _updateStatusScrollArrows());
// if (_postPreToken != null && _postPreToken!.isNotEmpty) {
//
@ -178,6 +193,7 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
@override
void dispose() {
_statusScrollController.dispose();
for (var controller in controllers.values) {
controller.dispose();
}
@ -274,14 +290,29 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
}
}
String _claimStatusLabel(Map<String, dynamic> item) {
return (item['status_display'] ?? item['status'] ?? '').toString();
}
int getStatusCount(String status) {
return filteredData
.where((item) =>
(item['status'] ?? '').toString().toLowerCase() ==
status.toLowerCase())
_claimStatusLabel(item).toLowerCase() == status.toLowerCase())
.length;
}
List<String> _uniqueDisplayNames(List<dynamic> statusMaster) {
final seen = <String>{};
final result = <String>[];
for (final status in statusMaster) {
final name = status['display_name']?.toString() ?? '';
if (name.isNotEmpty && seen.add(name.toLowerCase())) {
result.add(name);
}
}
return result;
}
Future<void> applyFilter() async {
logDebug("Filtersss");
@ -734,6 +765,7 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
}
Widget _buildDataRow(Map<String, dynamic> item) {
final statusLabel = _claimStatusLabel(item);
return Container(
padding: const EdgeInsets.symmetric(vertical: 6, horizontal: 16),
margin: const EdgeInsets.only(top: 10),
@ -795,10 +827,12 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: getStatusColor(item['status_display'] ?? ''),
color: getStatusColor(statusLabel),
borderRadius: BorderRadius.circular(10),
),
child: Text(item['status_display'] ?? '-', style: _dataBoldStatus)),
child: Text(
statusLabel.isEmpty ? '-' : statusLabel,
style: _dataBoldStatus)),
],
),
),
@ -874,48 +908,131 @@ class _NonEBClaimsListState extends State<NonEBClaimsList> {
);
}
void _updateStatusScrollArrows() {
if (!_statusScrollController.hasClients) return;
final position = _statusScrollController.position;
final canLeft = position.pixels > position.minScrollExtent + 1;
final canRight = position.pixels < position.maxScrollExtent - 1;
if (canLeft != _canScrollStatusLeft || canRight != _canScrollStatusRight) {
setState(() {
_canScrollStatusLeft = canLeft;
_canScrollStatusRight = canRight;
});
}
}
void _scrollStatusBy(double delta) {
if (!_statusScrollController.hasClients) return;
final target = (_statusScrollController.offset + delta)
.clamp(0.0, _statusScrollController.position.maxScrollExtent);
_statusScrollController.animateTo(
target,
duration: const Duration(milliseconds: 280),
curve: Curves.easeOutCubic,
);
}
Widget _buildStatusScrollButton({
required IconData icon,
required bool enabled,
required VoidCallback onTap,
}) {
return SizedBox(
width: 32,
height: 40,
child: Material(
color: enabled ? const Color(0xFF00999E) : const Color(0xFFE8E8E8),
borderRadius: BorderRadius.circular(8),
child: InkWell(
onTap: enabled ? onTap : null,
borderRadius: BorderRadius.circular(8),
child: Icon(
icon,
size: 22,
color: enabled ? Colors.white : Colors.black38,
),
),
),
);
}
Widget _buildStatusSummary() {
final List<dynamic> statusMaster = _claimStatusMaster;
if (statusMaster.isEmpty) return const SizedBox();
final List<dynamic> displayStatuses = appliedClaimStatus != null
final List<String> displayStatuses = appliedClaimStatus != null
? statusMaster
.where((status) =>
int.parse(status['id'].toString()) == appliedClaimStatus)
.toList()
: statusMaster;
.where((status) =>
int.parse(status['id'].toString()) == appliedClaimStatus)
.map((status) => status['display_name']?.toString() ?? '')
.where((name) => name.isNotEmpty)
.toList()
: _uniqueDisplayNames(statusMaster);
return SizedBox(
height: 35,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: displayStatuses.length,
separatorBuilder: (_, __) => const SizedBox(width: 10),
itemBuilder: (context, index) {
final statusName =
displayStatuses[index]['display_name']?.toString() ?? '';
return Row(
children: [
_buildStatusScrollButton(
icon: Icons.chevron_left,
enabled: _canScrollStatusLeft,
onTap: () => _scrollStatusBy(-240),
),
const SizedBox(width: 8),
Expanded(
child: ScrollConfiguration(
behavior: _StatusDragScrollBehavior(),
child: MouseRegion(
cursor: SystemMouseCursors.grab,
child: SizedBox(
height: 40,
child: NotificationListener<ScrollMetricsNotification>(
onNotification: (_) {
_updateStatusScrollArrows();
return false;
},
child: ListView.separated(
controller: _statusScrollController,
scrollDirection: Axis.horizontal,
physics: const ClampingScrollPhysics(),
itemCount: displayStatuses.length,
separatorBuilder: (_, __) => const SizedBox(width: 10),
itemBuilder: (context, index) {
final statusName = displayStatuses[index];
final count = getStatusCount(statusName);
final color = getStatusColor(statusName);
final count = getStatusCount(statusName);
final color = getStatusColor(statusName);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
child: Text(
'$statusName - $count',
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 12, vertical: 8),
decoration: BoxDecoration(
color: color,
borderRadius: BorderRadius.circular(6),
),
child: Text(
'$statusName - $count',
softWrap: false,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w500,
color: Colors.white,
),
),
);
},
),
),
),
),
);
},
),
),
),
const SizedBox(width: 8),
_buildStatusScrollButton(
icon: Icons.chevron_right,
enabled: _canScrollStatusRight,
onTap: () => _scrollStatusBy(240),
),
],
);
}
@ -1620,6 +1737,16 @@ class _ClaimsHeaderDelegate extends SliverPersistentHeaderDelegate {
bool shouldRebuild(_) => false;
}
class _StatusDragScrollBehavior extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,
PointerDeviceKind.stylus,
PointerDeviceKind.trackpad,
};
}
// ================= ICON BUTTON =================
class _IconActionButton extends StatelessWidget {
final IconData icon;