import 'dart:async'; import 'dart:io'; import 'package:connectivity_plus/connectivity_plus.dart'; import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:gen_service/Models/DashboardResponse.dart'; import 'package:gen_service/Screens/ContactUsScreen.dart'; import 'package:gen_service/Screens/HelpAndComplaintScreens/ComplaintDetailsScreen.dart'; import 'package:gen_service/Screens/HelpAndComplaintScreens/SelectOrderHelpScreen.dart'; import 'package:gen_service/Screens/HelpAndComplaintScreens/ComplaintListScreen.dart'; import 'package:gen_service/Screens/ProfileScreen.dart'; import 'package:gen_service/Screens/TransactionScreens/TransactionListScreen.dart'; import 'package:gen_service/Screens/TransactionScreens/contactMap.dart'; import 'package:provider/provider.dart'; import 'package:razorpay_flutter/razorpay_flutter.dart'; import '../Notifiers/DashboardProvider.dart'; import '../Notifiers/PayAmountProvider.dart'; import '../Utility/AppColors.dart'; import '../Utility/CustomSnackbar.dart'; import 'generatorDetailsScreen.dart'; class HomeScreen extends StatefulWidget { final String accId; final String sessionId; final String mobNumber; const HomeScreen({ Key? key, required this.accId, required this.sessionId, required this.mobNumber, }) : super(key: key); @override State createState() => _HomeScreenState(); } class _HomeScreenState extends State { Timer? _connectivityTimer; bool _hasInternet = true; late Razorpay _razorpay; bool? isSuccess; var paymentMethod = ""; var User_contact = "0"; bool _stretch = true; DateTime? currentBackPressTime; @override void initState() { super.initState(); // Initialize connectivity check _initConnectivity(); _razorpay = Razorpay(); Future.microtask(() { final dashboardProvider = Provider.of( context, listen: false, ); dashboardProvider.fetchDashboard(widget.accId, widget.sessionId); }); } Future _initConnectivity() async { try { _checkConnectivity(); _connectivityTimer = Timer.periodic(const Duration(seconds: 3), (timer) { _checkConnectivity(); }); } catch (e) { debugPrint("Connectivity initialization error: $e"); _updateConnectionStatus(false); } } Future _checkConnectivity() async { try { final connectivity = Connectivity(); final results = await connectivity.checkConnectivity(); final hasInternet = results.any((element) => element == ConnectivityResult.wifi || element == ConnectivityResult.mobile); if (hasInternet) { try { final result = await InternetAddress.lookup('google.com'); final socketCheck = result.isNotEmpty && result[0].rawAddress.isNotEmpty; _updateConnectionStatus(socketCheck); } catch (e) { _updateConnectionStatus(false); } } else { _updateConnectionStatus(false); } } catch (e) { debugPrint("Connectivity check error: $e"); _updateConnectionStatus(false); } } void _updateConnectionStatus(bool hasInternet) { if (mounted) { setState(() { _hasInternet = hasInternet; }); } if (!hasInternet) { _showNoInternetSnackbar(); } else { ScaffoldMessenger.of(context).hideCurrentSnackBar(); } } void _showNoInternetSnackbar() { if (mounted) { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).hideCurrentSnackBar(); CustomSnackBar.showError( context: context, message: "No internet connection! Please connect to the internet.", action: SnackBarAction( label: "RETRY", onPressed: _checkConnectivity, ), ); }); } } //_________________________________________________________ void _handlePaymentSuccess(PaymentSuccessResponse response) { setState(() async { final provider = Provider.of(context, listen: false); await provider.getPaymentStatus( sessionId: widget.sessionId, empId: widget.accId, razorpayOrderId: response.orderId.toString(), ); final data = provider.statusResponse; // Navigator.push( // context, // MaterialPageRoute(builder: (context) => PaymentSuccessFaillScreen( // total: "${data?.amount}", // date: "${data?.date}", // payMode: "UPI", // status: "Success", // )), // ); _razorpay.clear(); CustomSnackBar.showSuccess( context: context, message: data?.message ?? "Payment Success!", ); // buttonLoading = false; }); } void _handlePaymentError(PaymentFailureResponse response) { setState(() async { CustomSnackBar.showError( context: context, message: "Payment failed, please try again.", ); }); _razorpay.clear(); CustomSnackBar.showError( context: context, message: "Payment failed, please try again.", ); } void _handleExternalWallet(ExternalWalletResponse response) { _razorpay.clear(); } Future payAmountFunction(String amount) async { try { final provider = Provider.of(context, listen: false); await provider.payAmount( sessionId: widget.sessionId, empId: widget.accId, amount: amount, refType: "Gen Service", refId: "1", ); final data = provider.payResponse; if (data != null) { if (data.error == "0") { openCheckout(data.orderId, data.razorKey!); } else { CustomSnackBar.showError( context: context, message: "${data.message}", ); debugPrint("❌ Could not Complete Payment: ${data.message}"); } } else { debugPrint("❌ No response received from PayAmount API"); } } catch (e) { debugPrint("❌ 'Error occurred: $e'"); } } //razorpay payments__________________________________________________________ void openCheckout(razorPayOrderId, String razorpayKey) async { _razorpay.on(Razorpay.EVENT_PAYMENT_SUCCESS, _handlePaymentSuccess); _razorpay.on(Razorpay.EVENT_PAYMENT_ERROR, _handlePaymentError); _razorpay.on(Razorpay.EVENT_EXTERNAL_WALLET, _handleExternalWallet); // _buildCheckWidget(); Map options = { 'key': razorpayKey, 'amount': int.parse("${((0) * 100).round()}"), 'name': 'Gen Service', 'order_id': razorPayOrderId, 'description': "Bill", 'currency': 'INR', 'method': 'upi', 'prefill': {'contact': widget.mobNumber, 'email': ''}, }; // print(options); try { _razorpay.open(options); } catch (e, s) { // FirebaseCrashlytics.instance.log('Error occurred: $e'); // FirebaseCrashlytics.instance.recordError(e, s); debugPrint(e.toString()); } } void verifyPayment(String orderId) { isSuccess = true; setState(() { // toast(context, "Order Placed Successfully"); // print("Verify Payment"); }); _razorpay.clear(); } // void onError(CFErrorResponse errorResponse, String orderId) { // isSuccess = false; // setState(() { // // print(errorResponse.getMessage()); // // print("Error while making payment"); // }); // } @override void dispose() { _connectivityTimer?.cancel(); super.dispose(); } Future _onWillPop() async { DateTime now = DateTime.now(); if (currentBackPressTime == null || now.difference(currentBackPressTime!) > Duration(seconds: 2)) { currentBackPressTime = now; CustomSnackBar.showExit( context: context, title: "Exit", message: 'Press back again to exit', ); return false; } // Close the entire app immediately exit(0); } @override Widget build(BuildContext context) { final dashboardProvider = Provider.of(context); final isLoading = dashboardProvider.isLoading; final error = dashboardProvider.errorMessage; final data = dashboardProvider.dashboardData; if (isLoading) { return const Scaffold( backgroundColor: AppColors.backgroundRegular, body: Center( child: CircularProgressIndicator(color: AppColors.buttonColor), ), ); } if (error != null) { return Scaffold( backgroundColor: AppColors.backgroundRegular, body: Center( child: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // Error Icon Container( width: 120, height: 120, decoration: BoxDecoration( color: Colors.red.withOpacity(0.1), shape: BoxShape.circle, ), child: const Icon( Icons.error_outline_rounded, size: 60, color: Colors.red, ), ), const SizedBox(height: 24), // Error Title const Text( "Oops! Something went wrong", style: TextStyle( fontSize: 20, fontWeight: FontWeight.w600, color: Colors.black87, fontFamily: "Poppins", ), ), const SizedBox(height: 12), // Error Message Text( error, textAlign: TextAlign.center, style: const TextStyle( fontSize: 14, color: Colors.grey, fontFamily: "Poppins", height: 1.4, ), ), const SizedBox(height: 32), // Retry Button ElevatedButton.icon( onPressed: () async { // Show loading state setState(() {}); await Future.delayed(const Duration(milliseconds: 300)); // Retry fetching data final dashboardProvider = Provider.of(context, listen: false); await dashboardProvider.fetchDashboard( widget.accId, widget.sessionId ); }, style: ElevatedButton.styleFrom( backgroundColor: AppColors.buttonColor, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 12, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(25), ), elevation: 2, ), icon: const Icon(Icons.refresh_rounded, size: 20), label: const Text( "Try Again", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, fontFamily: "Poppins", ), ), ), const SizedBox(height: 16), // Alternative Action // TextButton( // onPressed: () { // // Go back or navigate to home // Navigator.maybePop(context); // }, // child: const Text( // "Go Back", // style: TextStyle( // fontSize: 14, // color: Colors.grey, // fontFamily: "Poppins", // ), // ), // ), ], ), ), ), ); } if (data == null) { return RefreshIndicator.adaptive( color: AppColors.amountText, onRefresh: () async { await Future.delayed(const Duration(milliseconds: 600)); Provider.of(context, listen: false); dashboardProvider.fetchDashboard(widget.accId, widget.sessionId); }, child: const Scaffold( backgroundColor: AppColors.backgroundRegular, body: Center(child: Text("No data found.")), ), ); } return WillPopScope( onWillPop: _onWillPop, child: RefreshIndicator.adaptive( color: AppColors.amountText, onRefresh: () async { await Future.delayed(const Duration(milliseconds: 600)); Provider.of(context, listen: false); dashboardProvider.fetchDashboard(widget.accId, widget.sessionId); }, child: SafeArea( top: false, bottom: Platform.isIOS?false:true, maintainBottomViewPadding: true, child: Scaffold( resizeToAvoidBottomInset: true, backgroundColor: Color(0xFF4076FF), body: CustomScrollView( physics: ClampingScrollPhysics(), slivers: [ SliverAppBar( leading: Container(), stretch: _stretch, backgroundColor: Color(0xFF4076FF), onStretchTrigger: () async { // Refresh data when pulled down final dashboardProvider = Provider.of( context, listen: false, ); dashboardProvider.fetchDashboard( widget.accId, widget.sessionId, ); }, stretchTriggerOffset: 300.0, expandedHeight: 232.0, flexibleSpace: LayoutBuilder( builder: (context, constraints) { final top = constraints.biggest.height; return FlexibleSpaceBar( stretchModes: const [ StretchMode.zoomBackground, StretchMode.blurBackground, ], background: GestureDetector( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ProfileScreen( accId: widget.accId, sessionId: widget.sessionId, ), ), ); }, child: Container( width: double.infinity, decoration: const BoxDecoration( gradient: AppColors.backgroundGradient, ), child: SafeArea( bottom: false, child: Padding( padding: const EdgeInsets.only( top: 10, bottom: 12, left: 20, right: 20, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ // Profile Image Container( height: 80, width: 80, decoration: const BoxDecoration( color: Color(0xFFE6F6FF), shape: BoxShape.circle, ), clipBehavior: Clip.antiAlias, child: (data.userProfile?.isNotEmpty == true) ? Image.network( data.userProfile.toString(), fit: BoxFit.cover, errorBuilder: ( context, error, stackTrace, ) => CircleAvatar( radius: 40, backgroundColor: const Color(0xFFE0F4FF), child: SvgPicture.asset( height: 40, "assets/svg/person_ic.svg", fit: BoxFit.contain, ), ), ) : CircleAvatar( radius: 40, backgroundColor: const Color( 0xFFE0F4FF, ), child: SvgPicture.asset( height: 40, "assets/svg/person_ic.svg", fit: BoxFit.contain, ), ), ), const SizedBox(height: 16), Flexible( child: Text( data.userName.toString(), style: const TextStyle( color: Colors.white, fontSize: 22, fontWeight: FontWeight.w400, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ), const SizedBox(height: 8), Text( '+91 ${data.mobNum}', style: TextStyle( fontWeight: FontWeight.w400, color: Colors.white.withOpacity(0.9), fontSize: 16, ), maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ), ), ), ); }, ), ), // Body content SliverToBoxAdapter( child: Container( padding: const EdgeInsets.only(top: 1, bottom: 0), color: Colors.transparent, child: Container( padding: const EdgeInsets.symmetric(horizontal: 0), decoration: const BoxDecoration( color: AppColors.backgroundRegular, borderRadius: BorderRadius.only( topLeft: Radius.circular(30), topRight: Radius.circular(30), ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), // Orders Section _buildOrdersSection(data), const SizedBox(height: 4), // Transactions Card _buildTransactionsCard(data), const SizedBox(height: 18), const Divider(), // Complaints Section _buildComplaintsSection(data), const SizedBox(height: 20), InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => SelectOrderHelpScreen( accId: widget.accId, sessionId: widget.sessionId, ), ), ); }, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 14), child: Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: const Color(0xFFD7F0FF), borderRadius: BorderRadius.circular(16), border: Border.all( width: 1.5, color: AppColors.buttonColor, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: const [ Text( 'Facing Issues?', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.amountText, ), ), Text( 'Raise a ticket to resolve your issues.', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: AppColors.subtitleText, ), ), ], ), SvgPicture.asset( "assets/svg/requirements.svg", height: 32, width: 32, ), ], ), ), ), ), const SizedBox(height: 25), // Get in Touch Card InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ContactMap( accId: widget.accId, sessionId: widget.sessionId, ), ), ); }, child: Container( width: double.infinity, padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 20, ), decoration: BoxDecoration( color: AppColors.amountText, borderRadius: const BorderRadius.only( topLeft: Radius.circular(24), topRight: Radius.circular(24), ), ), child: Padding( padding: const EdgeInsets.symmetric( horizontal: 16, ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Get in touch With Us', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: Colors.white, ), ), const SizedBox(height: 4), Text( 'Please feel free to reach out to us anytime', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: Color(0xAAFFFFFF), ), ), ], ), ), const Icon( Icons.arrow_circle_right_sharp, color: Color(0xFFFFFFFF), size: 30, ), ], ), ), ), ), // Add bottom padding ], ), ), ), ), ], ), ), ), ), ); } // ORDERS SECTION Widget _buildOrdersSection(dashboardData) { final orders = dashboardData.orders ?? []; if (orders.isEmpty) { return const Padding( padding: EdgeInsets.symmetric(vertical: 20, horizontal: 14), child: Center(child: Text("No Orders Found")), ); } return InkResponse( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 16), ...orders.map((order) { return Column( children: [ InkResponse( onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => Generatordetailsscreen( accId: widget.accId, sessionId: widget.sessionId, genId: order.id, ), ), ); }, child: _buildOrderItem( assetId: "#${order.hashId ?? ''} | Engine : ${order.engine ?? ''}", description: order.prodName ?? '', amc: (order.amc?.toString() ?? ''), warranty: (order.warranty?.toString() ?? ''), pImage: order.productImage ?? '', date: order.schedule?.isNotEmpty == true ? order.schedule!.first : null, serviceText: order.schedule?.isNotEmpty == true ? 'Upcoming Service Scheduled' : null, ), ), const SizedBox(height: 12), ], ); }).toList(), // See All Button ], ), ), ); } Widget _buildOrderItem({ required String assetId, required String description, required String amc, required String warranty, required String pImage, String? date, String? serviceText, }) { return Container( padding: EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( assetId, style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: AppColors.amountText, ), ), const SizedBox(height: 4), Text( description, style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: AppColors.normalText, height: 1.4, ), ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.start, children: [ // Status Badge with checkmark for AMC Protected if (amc == "1" || amc == "2") Container( padding: const EdgeInsets.symmetric( horizontal: 5, vertical: 4, ), decoration: BoxDecoration( gradient: amc == "1" ? AppColors.greenStripGradient : AppColors.fadeGradient, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ SvgPicture.asset( "assets/svg/tick_ic.svg", height: 14, color: amc == "1" ? AppColors.greenICBg : AppColors.subtitleText, ), const SizedBox(width: 2), Text( "AMC ", style: TextStyle( fontSize: 11, fontFamily: "HemiHead", fontStyle: FontStyle.italic, fontWeight: FontWeight.w700, color: amc == "1" ? AppColors.greenICBg : AppColors.subtitleText, ), ), Text( "Protected", style: TextStyle( fontSize: 11, fontFamily: "HemiHead", fontStyle: FontStyle.italic, fontWeight: FontWeight.w700, color: amc == "1" ? AppColors.normalText : AppColors.subtitleText, ), ), SizedBox(width: 4), if (amc == "2") const Icon( Icons.error_outline, color: Colors.red, size: 12, ), ], ), ], ), ), if (amc == "1" || amc == "2") SizedBox(width: 10), // for warranty if (warranty == "1" || warranty == "2") Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 4, ), decoration: BoxDecoration( gradient: warranty == "1" ? AppColors.yellowStripGradient : AppColors.fadeGradient, borderRadius: BorderRadius.circular(12), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Row( children: [ SvgPicture.asset( height: 14, warranty == "1" ? "assets/svg/tick2_ic.svg" : "assets/svg/tick3_ic.svg", ), const SizedBox(width: 2), Text( "Warranty", style: TextStyle( fontSize: 11, fontFamily: "HemiHead", fontStyle: FontStyle.italic, fontWeight: FontWeight.w700, color: warranty == "1" ? AppColors.normalText : AppColors.subtitleText, ), ), SizedBox(width: 4), if (warranty == "2") const Icon( Icons.error_outline, color: Colors.red, size: 12, ), ], ), ], ), ), ], ), ], ), ), const SizedBox(width: 12), Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xffF2F2F2), borderRadius: BorderRadius.circular(12), ), child: Image.network( pImage.isNotEmpty ? pImage : "https://erp.gengroup.in/assets/upload/inventory_add_genesis_product_pic/_1761047459_6425.png", height: 50, width: 50, fit: BoxFit.contain, errorBuilder: (context, error, stack) => Image.asset( 'assets/images/dashboard_gen.png', height: 40, width: 40, ), ), ), ], ), // Date and Service Text for first item if (date != null && serviceText != null) ...[ const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12), decoration: BoxDecoration( color: const Color(0xffF2F2F2), borderRadius: BorderRadius.circular(16), ), child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ SvgPicture.asset( height: 30, "assets/svg/checked_ic.svg", fit: BoxFit.contain, ), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( date, style: TextStyle( fontSize: 16, color: AppColors.normalText, fontWeight: FontWeight.w400, ), ), Text( serviceText, style: TextStyle( fontSize: 12, color: AppColors.subtitleText, fontWeight: FontWeight.w400, ), ), ], ), ], ), ), ], ], ), ); } // TRANSACTIONS CARD Widget _buildTransactionsCard(dashboardData) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 4), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Transactions', style: TextStyle( fontSize: 15, fontWeight: FontWeight.w500, color: Colors.black87, ), ), InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => TransactionListScreen( accId: widget.accId, sessionId: widget.sessionId, ), ), ); }, child: const Text( 'See All', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.amountText, ), ), ), ], ), const SizedBox(height: 8), Container( width: double.infinity, padding: EdgeInsets.all(20), decoration: BoxDecoration( gradient: dashboardData.balanceType == 'Pending Balance' ? AppColors.balanceCardGradientP : AppColors.balanceCardGradientA, borderRadius: BorderRadius.circular(16), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( flex: 6, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "₹", style: TextStyle( color: Colors.white, fontSize: 20, height: 2, fontWeight: FontWeight.w500, ), ), Text( dashboardData?.balanceAmount?.toString() ?? "0", style: TextStyle( color: Colors.white, fontSize: 34, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 4), Row( children: [ const Icon( Icons.error_outline, color: Colors.white, size: 16, ), const SizedBox(width: 6), Text( dashboardData.balanceType ?? '', style: const TextStyle( color: Colors.white, fontWeight: FontWeight.w400, fontSize: 12, ), ), ], ), ], ), ), Expanded( flex: 6, child: Column( children: [ Text( "*Make sure to pay before you incur any fines.", maxLines: 2, textAlign: TextAlign.end, style: TextStyle( color: const Color(0xAAFFFFFF), fontSize: 11, fontWeight: FontWeight.w400, ), ), const SizedBox(height: 10), if (dashboardData.balanceType == 'Pending Balance') InkResponse( onTap: () => _openPaymentSheet( context, dashboardData?.balanceAmount!, ), child: Container( padding: const EdgeInsets.symmetric( horizontal: 23, vertical: 7, ), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), ), child: const Text( " Pay Now ", style: TextStyle( color: Colors.blue, fontFamily: "Poppins", fontSize: 14, fontWeight: FontWeight.w500, ), ), ), ), ], ), ), ], ), ), ], ), ); } // COMPLAINTS SECTION Widget _buildComplaintsSection(DashboardResponse dashboardData) { final complaints = dashboardData.complaints ?? []; if (complaints.isEmpty) { return Padding( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 14), child: Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( "Complaints", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black87, ), ), InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ComplaintListScreen( accId: widget.accId, sessionId: widget.sessionId, genId: "", ), ), ); }, child: const Text( 'See All', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.amountText, ), ), ), ], ), SizedBox(height: 20,), Padding( padding: const EdgeInsets.symmetric(vertical: 10), child: const Center( child: Text( "No Open Complaints Found", style: TextStyle(fontSize: 14, color: Colors.grey), ), ), ), ], ), ); } return Padding( padding: const EdgeInsets.symmetric(horizontal: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( "Complaints", style: TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black87, ), ), InkResponse( onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ComplaintListScreen( accId: widget.accId, sessionId: widget.sessionId, genId: "", ), ), ); }, child: const Text( 'See All', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: AppColors.amountText, ), ), ), ], ), const SizedBox(height: 8), ...complaints.map((c) { return InkResponse( onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => ComplaintDetailsScreen( accId: widget.accId, sessionId: widget.sessionId, complaintId: c.id, ), ), ); }, child: Container( margin: const EdgeInsets.only(bottom: 10), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(12), border: Border.all(color: Colors.grey.shade200), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.03), blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ /// 🔹 Top row — Complaint name and status Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Complaint info Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "#${c.hashId ?? ''} | ${c.complaintName ?? ''}", style: const TextStyle( fontSize: 14, color: AppColors.amountText, ), ), const SizedBox(height: 4), Text( c.registredDate ?? '', style: TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: AppColors.subtitleText, ), ), ], ), ), // Status badge Container( padding: const EdgeInsets.symmetric( horizontal: 16, vertical: 6, ), decoration: BoxDecoration( color: (c.openStatus?.toLowerCase() == 'open') ? AppColors.successBG : AppColors.yellowBG, borderRadius: BorderRadius.circular(10), ), child: Text( c.openStatus ?? '', style: TextStyle( fontSize: 14, fontWeight: FontWeight.w400, color: (c.openStatus?.toLowerCase() == 'open') ? AppColors.success : AppColors.normalText, ), ), ), ], ), const SizedBox(height: 12), const Divider(), /// 🔹 Product Info Row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // Product details Expanded( flex: 5, child: Text( c.productName ?? "Unknown Product", style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: AppColors.normalText, ), ), ), // Product ID Row( children: [ Text( "#${c.id ?? ''} | ", style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w400, color: AppColors.subtitleText, ), ), if ((c.modelName ?? '').isNotEmpty) Text( "Engine: ${c.modelName}", style: TextStyle( fontSize: 12, color: AppColors.subtitleText, ), ), ], ), ], ), ], ), ), ); }).toList(), ], ), ); } void _openPaymentSheet(BuildContext context, String totalAmountStr) { TextEditingController amountController = TextEditingController(); bool isPartPayment = false; final double totalAmount = double.tryParse(totalAmountStr) ?? 0; showModalBottomSheet( isScrollControlled: true, backgroundColor: Colors.white, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.vertical(top: Radius.circular(24)), ), context: context, builder: (context) { return StatefulBuilder( builder: (context, setState) { return SafeArea( child: Padding( padding: EdgeInsets.only( bottom: MediaQuery.of(context).viewInsets.bottom, top: 16, left: 16, right: 16, ), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Handle Bar Center( child: Container( width: 40, height: 4, decoration: BoxDecoration( color: Colors.grey[300], borderRadius: BorderRadius.circular(4), ), ), ), const SizedBox(height: 16), // Title const Text( "Balance Amount Bill", style: TextStyle( fontSize: 14, fontWeight: FontWeight.w500, fontFamily: "Poppins", ), ), const SizedBox(height: 6), Divider(), const SizedBox(height: 10), // Pay Total Option GestureDetector( onTap: () { setState(() => isPartPayment = false); }, child: Row( children: [ Radio( value: false, groupValue: isPartPayment, onChanged: (v) => setState(() => isPartPayment = v!), activeColor: const Color(0xFF008CDE), ), // Radio( // value: false, // groupValue: isPartPayment, // onChanged: (v) => setState(() => isPartPayment = v!), // ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( "Pay Total", style: TextStyle( fontSize: 14, fontFamily: "Poppins", fontWeight: FontWeight.w400, ), ), Text( "Avoid late payment fees.", style: TextStyle( color: Color(0xff5FBB54), fontSize: 12, fontFamily: "Poppins", ), ), ], ), const Spacer(), Text( "₹${totalAmount.toStringAsFixed(0)}", style: const TextStyle( fontSize: 14, fontFamily: "Poppins", fontWeight: FontWeight.w400, ), ), ], ), ), const SizedBox(height: 10), // Part Payment Option GestureDetector( onTap: () { setState(() => isPartPayment = true); }, child: Row( children: [ Radio( value: true, groupValue: isPartPayment, onChanged: (v) => setState(() => isPartPayment = v!), activeColor: const Color(0xFF008CDE), ), const Text( "Part Payment", style: TextStyle( fontSize: 14, fontFamily: "Poppins", fontWeight: FontWeight.w400, ), ), const SizedBox(width: 24), Expanded( child: Container( height: 50, alignment: Alignment.center, padding: const EdgeInsets.symmetric(horizontal: 10), decoration: BoxDecoration( color: Colors.grey.shade100, borderRadius: BorderRadius.circular(12), ), child: TextFormField( controller: amountController, enabled: isPartPayment, style: const TextStyle( fontSize: 14, fontFamily: "Poppins", color: Colors.black87, ), keyboardType: TextInputType.number, decoration: const InputDecoration( hintText: "Enter amount", hintStyle: TextStyle( fontSize: 14, fontFamily: "Poppins", color: Colors.grey, ), border: InputBorder.none, ), ), ), ), ], ), ), const SizedBox(height: 6), Divider(), const SizedBox(height: 6), // Continue Button SizedBox( width: double.infinity, child: ElevatedButton( onPressed: () { double enteredAmount = isPartPayment ? double.tryParse(amountController.text) ?? 0 : totalAmount; if (enteredAmount <= 0) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text("Please enter a valid amount"), ), ); return; } if (isPartPayment && enteredAmount > totalAmount) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( "Entered amount cannot exceed total amount", ), ), ); return; } Navigator.pop(context); // Pass selected amount to your payAmountFunction payAmountFunction(enteredAmount.toStringAsFixed(2)); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF008CDE), foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(30), ), padding: const EdgeInsets.symmetric(vertical: 16), ), child: Padding( padding: const EdgeInsets.symmetric(horizontal: 22), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( "Continue Payment", style: TextStyle( fontFamily: "Poppins", color: Colors.white, fontSize: 16, ), ), SvgPicture.asset( "assets/svg/continue_ic.svg", color: Colors.white, height: 25, width: 25, ), ], ), ), ), ), const SizedBox(height: 16), ], ), ), ); }, ); }, ); } }