diff --git a/lib/presentation/nonEBClaimsList.dart b/lib/presentation/nonEBClaimsList.dart index d251ba7..2db260f 100644 --- a/lib/presentation/nonEBClaimsList.dart +++ b/lib/presentation/nonEBClaimsList.dart @@ -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 { String? _postPreToken = ''; TextEditingController searchController = TextEditingController(); TextEditingController searchClaimsStatusController = TextEditingController(); + final ScrollController _statusScrollController = ScrollController(); + bool _canScrollStatusLeft = false; + bool _canScrollStatusRight = false; Map controllers = {}; List reversedDataPolicy = []; @@ -77,25 +81,33 @@ class _NonEBClaimsListState extends State { 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 { 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 { @override void dispose() { + _statusScrollController.dispose(); for (var controller in controllers.values) { controller.dispose(); } @@ -274,14 +290,29 @@ class _NonEBClaimsListState extends State { } } + String _claimStatusLabel(Map 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 _uniqueDisplayNames(List statusMaster) { + final seen = {}; + final result = []; + for (final status in statusMaster) { + final name = status['display_name']?.toString() ?? ''; + if (name.isNotEmpty && seen.add(name.toLowerCase())) { + result.add(name); + } + } + return result; + } + Future applyFilter() async { logDebug("Filtersss"); @@ -734,6 +765,7 @@ class _NonEBClaimsListState extends State { } Widget _buildDataRow(Map 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 { 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 { ); } + 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 statusMaster = _claimStatusMaster; if (statusMaster.isEmpty) return const SizedBox(); - final List displayStatuses = appliedClaimStatus != null + final List 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( + 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 get dragDevices => { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + PointerDeviceKind.stylus, + PointerDeviceKind.trackpad, + }; +} + // ================= ICON BUTTON ================= class _IconActionButton extends StatelessWidget { final IconData icon;