import 'dart:convert'; import 'dart:math'; import 'dart:ui' as html; import 'dart:async'; import 'dart:html' as html; import 'dart:typed_data'; import 'package:flutter/services.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'dart:ui' as web; import 'package:google_fonts/google_fonts.dart'; import 'package:reorderables/reorderables.dart'; import 'package:web/web.dart' as web; import 'package:flutter/material.dart'; import 'package:frontend/Screens/policy/policyCriteria.dart'; import 'package:go_router/go_router.dart'; import 'package:http/http.dart' as http; import 'package:responsive_builder/responsive_builder.dart'; import '../../config/apiUrl.dart'; import '../../routes/custom_appBar.dart'; import '../../routes/custom_drawer.dart'; import '../../services/apiService.dart'; import '../../utils/auth_utils.dart'; import '../../widgets/custom_text_field.dart'; import '../../widgets/custom_user_form.dart'; class Policy extends StatefulWidget { final Map? policy; const Policy({super.key, required this.policy}); static Policy fromState(GoRouterState state) { return Policy(policy: state.extra as Map?); } @override _PolicyState createState() => _PolicyState(); } class _PolicyState extends State { final GlobalKey policyCriteriaKey = GlobalKey(); final ApiService apiService = ApiService(); List definedServices = [ 'Flight', 'Accomodation', 'Forex', 'Insurance', 'Visa', 'Miscellaneous', 'Taxi', 'Bus', 'Train', ]; List> services = []; String? servicesJson; Color? layoutColor; Color? bodyColor; late String policyType = "domestic"; // String selectedServiceDBValue = '1'; List serviceDBValueList = []; ValueNotifier selectedServiceIndex = ValueNotifier("1"); ValueNotifier selectedServicePriorityIndex = ValueNotifier("1"); ValueNotifier selectedServiceDBValue = ValueNotifier("0"); String? selectedService; // ValueNotifier selectedService = ValueNotifier("Train"); bool isViewMode = false; bool isDisable = false; bool isSubmitting = false; Map focusNodes = {}; Map focusStates = {}; Map errorMessages = {}; String? selectedPolicyId; String? _selectedTripType; String? PolicyName; String? SelectedDomestic = "0"; String? SelectedInternational = "0"; String? orgId; String? userId; bool showClass = true; bool showCost = false; // bool showCost = true; // on 21st june List? selectedAllServices; List> selectedOrgServiceIds = []; List? ServicesChoosed; List filledItineraryKeys = []; TextEditingController _policyController = TextEditingController(); List>? policy_details = []; Map get policyData { List> policyDetails = policy_details!.where((service) { // Only check these specific fields for emptiness final fieldsToCheck = [ 'cost', 'class', 'a1_action', 'a2_action', 'a3_action', ]; // If any of the important fields has a value, keep it return fieldsToCheck.any((field) { final value = service[field]; return value != null && value.toString().trim().isNotEmpty; }); }).toList(); Map data = { "name": _policyController.text, "domestic": SelectedDomestic, "international": SelectedInternational, "services_ids": services, "is_active": "1", "org_id": orgId, "created_by": userId, "policy_details": policyDetails, }; return data; } @override void initState() { super.initState(); _checkAuthAndLoadData(); focusNodes["policyFocusNode"] = FocusNode(); focusStates["policyFocused"] = false; for (var key in focusNodes.keys) { _addFocusListener(focusNodes[key]!, (focus) { setState(() { focusStates[key.replaceFirst("FocusNode", "Focused")] = focus; }); }); } // for (var field in dataHeader) { // focusNodes["${field}FocusNode"] = FocusNode(); // focusStates["${field}Focused"] = false; // } // WidgetsFlutterBinding.ensureInitialized(); // WidgetsBinding.instance.addPostFrameCallback((_) { // loadinitializeData(); // // updateSelectedServices(); // updateData(); // // loadInitialData(); // // if (widget.policy != null) { // final details = List>.from( // widget.policy!['policy_details'], // ); // policyCriteriaKey.currentState?.loadPolicyDetails(details); // // policyCriteriaKey.currentState?.fetchTrainFlightClass(); // } // }); } void _addFocusListener(FocusNode node, Function(bool) updateState) { node.addListener(() { setState(() { updateState(node.hasFocus); }); }); } void _checkAuthAndLoadData() async { final String? token = await getToken(); // Your async function to get token if (token == null || token.isEmpty) { // Token doesn't exist → redirect to login context.go( "/", ); // or use: router.go("/") if you're using `GoRouter` directly return; } if (!mounted) return; try { final roleUser = await getRoleUser(); if (roleUser != null && (roleUser == 'Org Admin' || roleUser == 'Travel Admin')) { loadinitializeData(); await updateSelectedServices(); updateData(); loadInitialData(); WidgetsBinding.instance.addPostFrameCallback((_) { if (widget.policy != null) { final details = List>.from( widget.policy!['policy_details'], ); policyCriteriaKey.currentState?.loadPolicyDetails(details); } }); // if (widget.policy != null) { // print("185"); // final details = List>.from( // widget.policy!['policy_details'], // ); // policyCriteriaKey.currentState?.loadPolicyDetails(details); // // policyCriteriaKey.currentState?.fetchTrainFlightClass(); // } } else { apiService.logout(context); } } catch (e) { print("group : $e"); } } void loadInitialData() async { String? layoutString = await getLayoutColor(); String? bodyStringColor = await getBodyColor(); setState(() { layoutColor = layoutString != null ? Color(int.parse(layoutString)) : Colors.redAccent; bodyColor = bodyStringColor != null ? Color(int.parse(bodyStringColor)) : Colors.white; }); } void loadinitializeData() async { orgId = await getOrgId(); userId = await getUserId(); } Future loadAllServices() async { try { final result = await apiService.fetchAllServices(context); setState(() { selectedAllServices = result; }); print("Fetched services: $selectedAllServices"); } catch (e) { print('Error fetching role list: $e'); } } Future loadOrgSelectedAlServices() async { try { final result = await apiService.fetchOrganization(context); if (result != null && result is Map) { final rawServices = result['services_ids']; if (rawServices != null && rawServices is String) { try { List decoded = json.decode(rawServices); List> formatted = decoded .map((e) => {"service_id": e['service_id'].toString()}) .toList(); setState(() { selectedOrgServiceIds = formatted; }); print("selectedOrgServiceIds: ${selectedOrgServiceIds}"); for (var service in selectedOrgServiceIds) { print("service_id: ${service['service_id']}"); } } catch (e) { print("Failed to decode services_ids: $e"); } } } } catch (e) { print('Error fetching role list: $e'); } } Future updateSelectedServices() async { print("started"); await loadAllServices(); await loadOrgSelectedAlServices(); print("III-end"); final selectedIds = selectedOrgServiceIds.map((e) => e['service_id']).toSet(); if (widget.policy != null) { print("inside if"); print(widget.policy); final details = List>.from( widget.policy!['policy_details'], ); print("****details-$details"); print( "UUFiltered Selected Services - ${widget.policy!['services_ids']} ", ); final exisitingService = List>.from( jsonDecode(widget.policy!['services_ids']), ); print("exisitingService ${exisitingService}"); // final filtered = // exisitingService! // .where( // (service) => // selectedIds.contains(service['service_id'].toString()), // ) // .toList(); setState(() { // ServicesChoosed = exisitingService; ServicesChoosed = selectedAllServices; // ServicesChoosed = filtered; }); print("298 ServicesChoosed ${ServicesChoosed}"); if (ServicesChoosed!.isNotEmpty) { print("Filtered Selected Services ChooesedIpfa1: $ServicesChoosed"); ServicesChoosed!.sort( (a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0), ); String firstServiceName = ServicesChoosed?.first['name']; String firstServiceId = ServicesChoosed?.first['service_id']; print( "✅ 306 First service name selected for filter: $firstServiceName - $firstServiceId", ); selectedService = firstServiceName; if (selectedServiceDBValue.value == "0") { setState(() { selectedServiceDBValue.value = firstServiceId.toString(); }); } List serviceDBvalue = ServicesChoosed! .map((item) => int.parse(item['service_id'].toString())) .toList(); serviceDBValueList = serviceDBvalue; } print(widget.policy); // updateData(); if (widget.policy != null && widget.policy!['services_ids'] != null) { final decoded = jsonDecode(widget.policy!['services_ids']); setState(() { services = List>.from(decoded) .map( (service) => { 'service_id': service['service_id'].toString(), 'name': service['name'].toString(), 'order': service['order'].toString(), }, ) .toList(); }); print("✅ Loaded services from policy (decoded): $services"); } print("Filtered Selected Services Added to Policy: $ServicesChoosed"); } else { // final filtered = // selectedAllServices! // .where( // (service) => // selectedIds.contains(service['service_id'].toString()), // ) // .toList(); print("ServicesChoosedYY: $ServicesChoosed"); setState(() { ServicesChoosed = selectedAllServices; // ServicesChoosed = filtered; // services = ServicesChoosed! // .map((service) => service['name'].toString()) // .toList(); // ServicesChoosed = filtered; services = ServicesChoosed! .map( (service) => { 'service_id': service['service_id'].toString(), 'name': service['name'].toString(), // ✅ no space before 'name' 'order': service['order'].toString(), }, ) .toList(); }); print("Filtered Selected Services Chooesed1: $ServicesChoosed"); if (ServicesChoosed!.isNotEmpty) { policyCriteriaKey.currentState?.fetchTrainFlightClass(); ServicesChoosed!.sort( (a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0), ); String firstServiceName = ServicesChoosed?.first['name']; String firstServiceId = ServicesChoosed?.first['service_id']; print( "✅ 363 First service name selected for filter: $firstServiceName - $firstServiceId", ); selectedService = firstServiceName; if (selectedServiceDBValue.value == "0") { setState(() { selectedServiceDBValue.value = firstServiceId.toString(); }); } List serviceDBvalue = ServicesChoosed! .map((item) => int.parse(item['service_id'].toString())) .toList(); serviceDBValueList = serviceDBvalue; } } } void updateData() { print("updateData"); // if (widget.policy != null && selectedService != null && selectedServiceDBValue.value != "0") { if (widget.policy != null) { setState(() { selectedPolicyId = widget.policy?["policy_id"] ?? ""; _policyController.text = widget.policy?["name"] ?? ""; SelectedDomestic = widget.policy?["domestic"] ?? ""; SelectedInternational = widget.policy?["international"] ?? ""; if (SelectedDomestic == "1") { _selectedTripType = "1"; } else if (SelectedInternational == "1") { _selectedTripType = "2"; } /// ✅ Load policy_details list safely policy_details = List>.from( widget.policy?["policy_details"] ?? [], ); // print("policy_details ${policy_details}"); }); } } // void handleSubmit() async { // setState(() { isDisable = true; }); // print("Services - $services"); // print("USR Detail Submit - $policyData"); // // policyCriteriaKey.currentState?.saveCurrentPolicy(services); // // // Now the full data is ready in policyDataFromChild // print("Submitting full policyData: $policyData"); // // Map data = policyData; // // if (!isValidData(data)) { // print("USERDETAILS : $policyData"); // print("Validation Failed: Required fields are missing."); // setState(() { isDisable = false; }); // return; // Stop execution if validation fails // } else { // // print("USERDETAILS : $policyData"); // // orgId = await getOrgId(); // // if(isDisable == true){ createPolicyData(data); } // setState(() { isDisable = false; }); // } // } void handleSubmit() async { if (isSubmitting || isDisable) return; isSubmitting = true; setState(() { isDisable = true; }); policyCriteriaKey.currentState?.saveCurrentPolicy(services); // Now the full data is ready in policyDataFromChild print("Submitting full policyData: $policyData"); Map data = policyData; if (!isValidData(data)) { print("Validation Failed"); isSubmitting = false; setState(() => isDisable = false); return; } bool result = false; try { result = await createPolicyData(context, data); } catch (e) { print("Unexpected error during policy creation: $e"); } if (result) { // ✅ Only navigate on success context.go('/PolicyList'); } else { // ❌ Show error, allow retry Fluttertoast.showToast( msg: "Failed to submit policy. Please try again.", toastLength: Toast.LENGTH_SHORT, gravity: ToastGravity.CENTER, timeInSecForIosWeb: 2, backgroundColor: Colors.redAccent, textColor: Colors.white, fontSize: 18.0, webBgColor: "linear-gradient(to right, #28a745, #28a745)", ); } isSubmitting = false; setState(() { isDisable = false; // Allow retry }); } bool isValidData(Map data) { errorMessages.clear(); // Reset previous errors // Validate required fields if (data["name"] == null || data["name"].toString().trim().isEmpty) { errorMessages["name"] = "Required"; // "Policy name is required."; } // Validate that either domestic or international is selected final domestic = data["domestic"]?.toString() ?? "0"; final international = data["international"]?.toString() ?? "0"; print( "domestic: ${data["domestic"]}, international: ${data["international"]}", ); if (domestic != "1" && international != "1") { errorMessages["trip_type"] = "Required"; // "Please select Domestic or International."; } // Validate at least one policy_detail with valid content final policyDetails = data["policy_details"] as List>; bool hasAtLeastOneDetail = policyDetails.any((service) { final fieldsToCheck = [ 'cost', 'class', 'a1_action', 'a2_action', 'a3_action', ]; return fieldsToCheck.any((field) { final value = service[field]; return value != null && value.toString().trim().isNotEmpty; }); }); if (!hasAtLeastOneDetail) { errorMessages["policy_details"] = "Required"; // "At least one valid policy detail is required."; } return errorMessages.isEmpty; } void _clearError(String field) { if (mounted && errorMessages.containsKey(field)) { setState(() { errorMessages.remove(field); }); } } Future createPolicyData( BuildContext context, Map policyData, ) async { final String apiUrldata = '$apiUrl/api/policy/createOrUpdate'; final token = await getToken(); // Fetch token if (token == null) { print('Token not found. Please log in.'); // throw Exception('Token not found. Please log in.'); return false; } final int? policyId; if (selectedPolicyId != null && selectedPolicyId!.isNotEmpty) { policyId = int.tryParse(selectedPolicyId!); policyData['policy_id'] = policyId; // Add only if updating } try { final response = await http.post( Uri.parse(apiUrldata), headers: { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'app-signature': 'ts-traveltool-2025-signature-123456', }, body: jsonEncode(policyData), // Convert map to JSON ); if (response.statusCode == 200) { print("policyData submitted successfully!"); await apiService.handleTokenRefresh(context, userId!); print("Response: ${response.body}"); return true; } else if (response.statusCode == 403) { print("403-FORB"); await apiService.logout(context); return false; // throw Exception('Failed to load users'); } else { print("Failed to submit policyData. Status: ${response.statusCode}"); print("Error: ${response.body}"); return false; } } catch (e) { print(" Error submitting policyData: $e"); return false; } } @override Widget build(BuildContext context) { return ResponsiveBuilder( builder: (context, sizingInfo) { bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; return Scaffold( backgroundColor: Color(0xFFf5f5f5), appBar: CustomAppBar(isDesktop: isDesktop), drawer: CustomDrawer(isDesktop: false), body: Padding( padding: isDesktop ? EdgeInsets.symmetric( horizontal: MediaQuery.of(context).size.width * 0.1, // 30% of screen width as horizontal padding vertical: MediaQuery.of(context).size.height * 0, // 5% of screen height as vertical padding ) : EdgeInsets.all(8), child: Column( children: [ Expanded( child: Row( children: [ // if (isDesktop) CustomDrawer(isDesktop: true), Expanded(child: buildData(isDesktop, context)), // Expanded( // child: Container( // color: bodyColor, // child: buildPolicyLayout(isDesktop), // ), // ), ], ), ), ], ), ), // Row( // children: [ // if (isDesktop) CustomDrawer(isDesktop: true), // Expanded( // child: Column( // children: [ // Expanded( // child: Container( // // height: MediaQuery.of(context).size.height * 0.8, // color: bodyColor, // child: buildPolicyLayout(isDesktop)), // ), // ], // ), // ), // Container( // color: Colors.white, // child: Padding( // padding: const EdgeInsets.all(8.0), // child: isDesktop // ? Row( // mainAxisAlignment: MainAxisAlignment.end, // children: _buildSubmit(isDesktop), // ) // : Row( // mainAxisAlignment: MainAxisAlignment.center, // children: _buildSubmit(isDesktop), // )), // ) // ], // ), ); }, ); } Widget buildData(bool isDesktop, context) { return Container( margin: isDesktop ? const EdgeInsets.only(top: 10.0, bottom: 10.0) : null, padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: isDesktop ? Colors.white : Color(0xFFFCFCFC), ), // margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0), // decoration: BoxDecoration( // color: Color(0xFFE1F5FE), // // color: bodyColor, // border: Border.all( // color: Colors.white, // // color: Color(0xFFF7F7FB), // // width: 3.5)), child: Column( children: [ Expanded( child: Container( // color: bodyColor, // color: Color(0xFFE1F5FE), child: buildPolicyLayout(isDesktop), ), ), Container( color: Colors.white, padding: const EdgeInsets.all(8.0), child: isDesktop ? Row( mainAxisAlignment: MainAxisAlignment.end, children: _buildSubmit(isDesktop), ) : Row( mainAxisAlignment: MainAxisAlignment.center, children: _buildSubmit(isDesktop), ), ), ], ), ); } Widget buildPolicyLayout(bool isDesktop) { return Container( // margin: isDesktop // ? EdgeInsets.all(10.0) // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), height: isDesktop ? MediaQuery.of(context).size.height * 0.98 : MediaQuery.of(context).size.height, // decoration: BoxDecoration( // border: isDesktop // ? Border.all( // width: 2, // color: Colors.white, // // color: Color(0xFFF7F7FB), // ) // : null, // color: Colors.white, // // color: Color(0xFFF7F7FB), // // // color: Colors.amber, // ), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( // color: Color(0xFFF7F7FB), child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ Container( padding: isDesktop ? EdgeInsets.all(6) : EdgeInsets.all(3), // color: Colors.white, // Background to avoid overlapping color: Colors.white, // color: isDesktop ? Color(0xFFF7F7FB) : Colors.white, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.end, // children: [ // Text( // "Choose Policy Type", // style: GoogleFonts.poppins( // fontSize: 12, // fontWeight: FontWeight.w600, // color: Color(0xFF575A74), // ), // ), // ], ), ), ], ), ), isDesktop ? SizedBox(height: 0) : SizedBox(height: 5), Container( padding: isDesktop ? const EdgeInsets.only(left: 35) : null, child: isDesktop ? Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded(child: _buildPolicyNameField(isDesktop)), Spacer(), Expanded(child: _buildPolicyTypeField(isDesktop)), ], ) : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildPolicyNameField(isDesktop), SizedBox(height: 20), _buildPolicyTypeField(isDesktop), ], ), ), SizedBox(height: 10), Divider(thickness: 0.1, color: Colors.grey), if (errorMessages["policy_details"] != null) ...[ SizedBox(height: 5), // Space before error message Text( errorMessages["policy_details"]!, style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], isDesktop ? Padding( padding: const EdgeInsets.only(left: 30.0, right: 98.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Approval Criteria", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), Text( "Service Priority", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), ], ), ) : SizedBox.shrink(), isDesktop ? Container( // color: Colors.yellow.shade50, height: MediaQuery.of(context).size.height * 0.56, child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Column( children: [ _buildPolicyOrdering(isDesktop), _buildPolicyCategory(isDesktop), ], ), Column(children: [_buildPolicyCategoryList(isDesktop)]), ], ), ), ) : Expanded( child: Container( child: SingleChildScrollView( scrollDirection: Axis.vertical, child: Column( children: [ _buildPolicyCategoryList(isDesktop), _buildPolicyOrdering(isDesktop), _buildPolicyCategory(isDesktop), ], ), ), ), ), // isDesktop // ? Expanded( // child: Row( // children: [ // _buildPolicyCategory(isDesktop), // _buildPolicyCategoryList(isDesktop), // ], // ), // ) // : Expanded( // child: Column( // children: [ // _buildPolicyCategoryList(isDesktop), // _buildPolicyCategory(isDesktop), // ], // ), // ), ], ), ); } // Widget _buildServiceSelect(bool isDesktop){ // return []; // } Widget _buildPolicyNameField(bool isDesktop) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Policy Name *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), CustomTextFieldUserWrapper( isFocused: focusStates["policyFocused"] ?? false, isDesktop: isDesktop, child: SizedBox( height: 40, child: TextField( style: GoogleFonts.poppins(fontSize: 12), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')), ], focusNode: focusNodes["policyFocusNode"], controller: _policyController, onChanged: (value) => _clearError("name"), decoration: InputDecoration( labelText: "Policy Name", labelStyle: GoogleFonts.poppins( fontSize: 12, color: Colors.grey, ), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), ), ), ), ), if (errorMessages["name"] != null) ...[ SizedBox(height: 5), Text( errorMessages["name"]!, style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], ); } Widget _buildPolicyTypeField(bool isDesktop) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Policy Type *", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74), ), ), SizedBox(height: 5), Row( mainAxisAlignment: MainAxisAlignment.start, children: _buildTripType(isDesktop), ), if (errorMessages["trip_type"] != null) ...[ SizedBox(height: 5), Text( errorMessages["trip_type"]!, style: GoogleFonts.poppins(color: Colors.red, fontSize: 12), ), ], ], ); } Widget _buildPolicyCategoryList(bool isDesktop) { return Container( margin: const EdgeInsets.only(top: 8.0), // color: Colors.white, height: isDesktop ? 350 : null, // height: isDesktop ? MediaQuery.of(context).size.height * 0.55 : null, // color: Colors.blueGrey.shade200, width: isDesktop ? MediaQuery.of(context).size.width * 0.15 : null, decoration: BoxDecoration( border: Border.all(color: Colors.blueGrey.shade100, width: 0.35), ), child: isDesktop ? Padding( padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: [_buildPolicySubCategoryList(isDesktop)], ), ) : Column( children: [ Container( // color: Colors.amber, child: _buildPolicySubCategoryList(isDesktop), // child: Text("FAta"), // child: Row( // mainAxisAlignment: MainAxisAlignment.start, // children: [_buildPolicySubCategoryList(isDesktop)], // ), ), ], ), ); } Widget _buildPolicySubCategoryList(bool isDesktop) { if (services.isEmpty) { return const Center(child: CircularProgressIndicator()); } if (isDesktop) { // 🖥 Desktop (vertical ReorderableListView) return Expanded( child: ReorderableListView( onReorder: (oldIndex, newIndex) { setState(() { if (newIndex > oldIndex) newIndex -= 1; final item = services.removeAt(oldIndex); services.insert(newIndex, item); }); }, children: List.generate(services.length, (i) { return SizedBox( key: ValueKey(services[i]['service_id']), width: 185, height: 35, // height: MediaQuery.of(context).size.height * 0.025, child: _buildServiceTile(services[i], i.toString()), ); }), ), ); } else { // 📱 Mobile (horizontal ReorderableWrap) return Container( // color: Colors.red, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("Service Ordering"), SingleChildScrollView( scrollDirection: Axis.horizontal, child: ReorderableWrap( spacing: 8, runSpacing: 8, direction: Axis.horizontal, needsLongPressDraggable: true, onReorder: (oldIndex, newIndex) { setState(() { final item = services.removeAt(oldIndex); services.insert(newIndex, item); }); }, children: List.generate(services.length, (i) { return SizedBox( key: ValueKey(services[i]), height: isDesktop ? 10 : 45, // child: _buildServiceTile(services[i]['service_id'], i.toString()), child: _buildServiceTile(services[i], i.toString()), ); }), ), ), ], ), ); } } Widget _buildServiceTile(Map service, String index) { // bool isSelected = selectedServiceIndex.value == index; bool isSelected = selectedServicePriorityIndex.value == index; String name = service['name']; // or 'service_id', as needed return GestureDetector( onTap: () { setState(() { // selectedServiceIndex.value = index; selectedServicePriorityIndex.value = index; }); }, child: Container( margin: const EdgeInsets.all(5), decoration: BoxDecoration( // color: Colors.yellow.shade50, color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.white), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), blurRadius: 2, offset: const Offset(0, 1), ), ], ), alignment: Alignment.center, child: Text( name, style: GoogleFonts.poppins(color: Colors.black, fontSize: 12), ), ), ); } Widget _buildServiceTile1(Map service, String index) { // bool isSelected = selectedServiceIndex.value == index; // bool isSelected = selectedServiceIndex.value == index; // String name = service['service_id'] bool isSelected = selectedServiceIndex.value == index; String name = service['name']; return GestureDetector( onTap: () { setState(() { selectedServiceIndex.value = index; }); }, child: Container( height: 5, // padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 2), margin: const EdgeInsets.all(1), decoration: BoxDecoration( color: Colors.white, // color: isSelected ? const Color(0xFF114D8B) : Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all(color: Colors.white), boxShadow: [ BoxShadow( color: Colors.grey.withOpacity(0.3), blurRadius: 2, offset: const Offset(0, 1), ), ], ), alignment: Alignment.center, child: Text( name, style: GoogleFonts.poppins( color: Colors.black, // color: isSelected ? Colors.white : Colors.black87, fontSize: 12, // fontWeight: FontWeight.w100, ), ), ), ); } Widget _buildPolicyOrdering(bool isDesktop) { return Container( // height: 50, // color: Colors.white, // color: Colors.yellow.shade200, padding: isDesktop ? const EdgeInsets.only(left: 30, top: 8) : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.62 : null, // width: isDesktop ? MediaQuery.of(context).size.width * 0.75 : null, child: isDesktop ? Container( // color: Colors.amber, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [_buildPolicyServiceOrdering(isDesktop)], ), ) : Container( // color: Colors.amber, child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [_buildPolicyServiceOrdering(isDesktop)], ), ), ); } Widget _buildPolicyServiceOrdering(bool isDesktop) { if (ServicesChoosed == null) { return const Center(child: CircularProgressIndicator()); } // Sort services by 'order' ServicesChoosed!.sort( (a, b) => (a['order'] ?? 0).compareTo(b['order'] ?? 0), ); List services = ServicesChoosed!.map((service) => service['name'].toString()).toList(); // List serviceDBvalue = // ServicesChoosed!.map((service) => int.parse(service['service_id'].toString())).toList(); List serviceDBvalue = ServicesChoosed! .map((item) => int.parse(item['service_id'].toString())) .toList(); print("1093"); print(services); print(serviceDBvalue); return Container( child: SingleChildScrollView( scrollDirection: Axis.horizontal, child: Flex( direction: Axis.horizontal, children: services.asMap().entries.map((entry) { print("1182 ${entry}"); int i = entry.key; int index = i + 1; String service = entry.value; int serviceId = serviceDBvalue[i]; bool isSelected = selectedServiceIndex.value == index.toString(); return SizedBox( // width: isDesktop ? 40 : null, height: isDesktop ? max( (MediaQuery.of(context).size.height * 0.075), 10, ) : 45, // max((MediaQuery.of(context).size.height * 0.09), 10) child: GestureDetector( onTap: () { print( "1201 Selected Services - $service - Tab Index - $index Service Id- $serviceId", ); setState(() { selectedServiceIndex.value = index.toString(); selectedServiceDBValue.value = serviceId.toString(); selectedService = service; print( " selectedServiceIndex.value - ${selectedServiceIndex.value}", ); // policyCriteriaKey.currentState?.fieldForPolicy(); // policyCriteriaKey.currentState // ?.addOrUpdatePolicy(selectedServiceIndex.value); print("policyselectedService - $selectedService"); if (selectedService == "Flight" || selectedService == "Train" || selectedService == "Accomodation") { showClass = true; showCost = false; // int serviceCode = selectedService == "Flight" ? 1 : 2; print("policyselectedService1 - $selectedService"); policyCriteriaKey.currentState ?.fetchTrainFlightClass(); } // else if (selectedService == "Accommodation") { // showClass = true; // showCost = false; // } else { showClass = false; showCost = false; } }); }, child: Container( margin: const EdgeInsets.all(5), padding: isDesktop ? const EdgeInsets.all(8) : const EdgeInsets.symmetric( horizontal: 8, vertical: 3, ), alignment: Alignment.center, child: Column( mainAxisSize: MainAxisSize.min, children: [ Text( service, style: GoogleFonts.poppins( color: isSelected ? const Color(0xFF114D8B) : Colors.black87, fontSize: 13, fontWeight: isSelected ? FontWeight.bold : FontWeight.w500, decoration: TextDecoration .none, // remove built-in underline ), ), if (isSelected) const SizedBox( height: 1, ), // spacing between text and underline if (isSelected) Container( height: 2, width: 30, // or based on text width color: const Color(0xFF114D8B), ), ], ), ), ), ); }).toList(), ), ), ); } Widget _buildPolicySubCategoryList1(bool isDesktop) { // List services = [ // "Flight", // "Train", // "Bus", // "Taxi", // "Forex", // "Accommodation", // "Insurance", // "Visa", // "Miscellaneous" // ]; if (ServicesChoosed == null) { return const Center(child: CircularProgressIndicator()); } List services = ServicesChoosed!.map((service) => service['name'].toString()).toList(); return Expanded( child: SingleChildScrollView( scrollDirection: isDesktop ? Axis.vertical : Axis.horizontal, child: Flex( direction: isDesktop ? Axis.vertical : Axis.horizontal, children: services.asMap().entries.map((entry) { int index = entry.key + 1; String service = entry.value; bool isSelected = selectedServiceIndex.value == index.toString(); return SizedBox( width: isDesktop ? 180 : null, height: isDesktop ? max( (MediaQuery.of(context).size.height * 0.075), 10, ) : 45, // max((MediaQuery.of(context).size.height * 0.09), 10) child: GestureDetector( onTap: () { print("Selected Services - $service - $index"); setState(() { // selectedServiceIndex.value = index.toString(); // selectedService = service; // // if (selectedService == "Flight" || // selectedService == "Train") { // showClass = true; // showCost = true; // int serviceCode = selectedService == "Flight" ? 1 : 2; // policyCriteriaKey.currentState?.fetchTrainFlightClass(); // } else if (selectedService == "Accommodation") { // showClass = true; // showCost = false; // } else { // showClass = false; // showCost = false; // } }); }, child: Container( margin: EdgeInsets.all(5), padding: isDesktop ? EdgeInsets.all(8) : EdgeInsets.only( top: 3, bottom: 3, left: 8, right: 8, ), decoration: BoxDecoration( // color: Colors.blue, color: isSelected ? Color(0xFF114D8B) : Colors.white, // : Color(0xFFEBEBF7), borderRadius: BorderRadius.circular(8), border: Border.all( color: Colors.white, // Light grey border width: 1, ), boxShadow: [ BoxShadow( color: Colors.grey.withAlpha(90), // Shadow color blurRadius: 1, // Blur radius spreadRadius: 1, // Spread radius offset: Offset(0, 1), // Shadow position ), ], ), alignment: Alignment.center, child: Text( service, style: GoogleFonts.poppins( color: isSelected ? Colors.white : Colors.black87, fontSize: 13, fontWeight: isSelected ? FontWeight.bold : FontWeight.w100, ), ), ), ), ); }).toList(), ), ), ); } Widget _buildPolicyCategory(bool isDesktop) { print("1408 $selectedServiceIndex"); print("1409 $selectedService"); print("1410 ${selectedServiceDBValue.value}"); return Container( margin: isDesktop ? EdgeInsets.all(5) : null, // color: Colors.brown.shade100, // child: Text("data"), // color: Colors.white60, child: (selectedService != null && selectedServiceDBValue.value != "0") ? PolicyCriteria( key: policyCriteriaKey, isDesktop: isDesktop, isClass: showClass, isCost: showCost, selectedTabNotifier: selectedServiceIndex, selectedIdNotifier: selectedServiceDBValue, selectedService: selectedService!, serviceDBValueList: serviceDBValueList, // 👈 Pass the array here userId: userId, onPolicyDataChanged: (List>? policyData) { print("🟢 policyData received from child: $policyData"); WidgetsBinding.instance.addPostFrameCallback((_) { setState(() { policy_details = policyData; _clearError("policy_details"); }); }); }, ) : const Center(child: CircularProgressIndicator()), ); } List _buildTripType(bool isDesktop) { return [ CustomTextFieldWrapper( color: Color(0xFFF4F4FB), layoutColor: layoutColor, borderRadius: BorderRadius.circular(25), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), width: 130, isFocused: _selectedTripType == "1", isDesktop: isDesktop, child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "Domestic", style: GoogleFonts.poppins( color: _selectedTripType == "1" ? Colors.black : Colors.black, fontWeight: _selectedTripType == "1" ? FontWeight.w600 : null, fontSize: 13, ), ), GestureDetector( onTap: () { setState(() { _clearError("trip_type"); _selectedTripType = "1"; PolicyName = "Domestic Policy"; SelectedDomestic = "1"; SelectedInternational = "0"; }); }, child: Container( width: 15, height: 15, decoration: BoxDecoration( shape: BoxShape.rectangle, // color: _selectedOption == option["value"] // ? Colors.blueAccent // : Colors.transparent, borderRadius: BorderRadius.circular(4), // Rounded rectangle border: Border.all( color: _selectedTripType == "1" ? Colors.green : Colors.black, width: _selectedTripType == "1" ? 2 : 1, ), ), child: _selectedTripType == "1" ? Icon(Icons.rectangle, size: 8, color: Colors.green) : null, // Add checkmark if selected ), ), ], ), ), SizedBox(width: 20), CustomTextFieldWrapper( color: Color(0xFFF4F4FB), layoutColor: layoutColor, borderRadius: BorderRadius.circular(25), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), width: 150, // padding: EdgeInsets.symmetric(horizontal: 5, vertical: 2), isFocused: _selectedTripType == "2", isDesktop: isDesktop, child: Row( mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( "International", style: GoogleFonts.poppins( fontSize: 13, color: _selectedTripType == "2" ? Colors.black : Colors.black, fontWeight: _selectedTripType == "2" ? FontWeight.w600 : null, ), ), GestureDetector( onTap: () { setState(() { _clearError("trip_type"); _selectedTripType = "2"; PolicyName = "International Policy"; SelectedDomestic = "0"; SelectedInternational = "1"; }); }, child: Container( width: 15, height: 15, decoration: BoxDecoration( shape: BoxShape.rectangle, // color: _selectedOption == option["value"] // ? Colors.blueAccent // : Colors.transparent, borderRadius: BorderRadius.circular(4), // Rounded rectangle border: Border.all( color: _selectedTripType == "2" ? Colors.green : Colors.black, width: _selectedTripType == "2" ? 2 : 1, ), ), child: _selectedTripType == "2" ? Icon(Icons.rectangle, size: 8, color: Colors.green) : null, // Add checkmark if selected ), ), ], ), // RadioListTile( // activeColor: Colors.blueAccent, // contentPadding: EdgeInsets.zero, // dense: true, // title: Text("International"), // value: "2", // groupValue: _selectedTripType, // onChanged: widget.isViewMode // ? null // : (value) { // setState(() { // _selectedTripType = value!; // }); // }, // ), ), ]; } List _buildSubmit(isDesktop) { return [ ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: layoutColor, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: layoutColor ?? Colors.grey, width: 2), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: () { context.go('/PolicyList'); }, child: Text("Cancel", style: GoogleFonts.poppins(fontSize: 10)), ), SizedBox(width: 20), MouseRegion( cursor: isViewMode ? SystemMouseCursors.forbidden : SystemMouseCursors.click, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: isViewMode ? layoutColor : layoutColor, // Keep original color foregroundColor: isViewMode ? Colors.white : Colors.white, // Keep original color disabledBackgroundColor: layoutColor, // Ensure color remains when disabled disabledForegroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: BorderSide(color: layoutColor ?? Colors.grey, width: 2), ), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: // isViewMode ? null : handleSubmit, // Disable when in view mode isViewMode || isDisable ? null : handleSubmit, child: Text("Submit", style: GoogleFonts.poppins(fontSize: 10)), ), ), ]; } List _buildTripType1(bool isDesktop) { return [ CustomTextFieldWrapper( color: Color(0xFFF4F4FB), padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2), width: isDesktop ? 170 : 140, isFocused: _selectedTripType == "1", isDesktop: isDesktop, child: SizedBox( height: 35, child: Material( color: Colors.transparent, child: RadioListTile( activeColor: Colors.blueAccent, contentPadding: EdgeInsets.zero, visualDensity: VisualDensity.compact, dense: true, title: Text("Domestic", style: GoogleFonts.poppins(fontSize: 12)), value: "1", groupValue: _selectedTripType, onChanged: (value) { setState(() { _selectedTripType = value!; PolicyName = "Domestic Policy"; SelectedDomestic = "1"; SelectedInternational = "0"; }); }, ), ), ), ), isDesktop ? SizedBox(width: 28) : SizedBox(width: 15), CustomTextFieldWrapper( color: Color(0xFFF4F4FB), padding: EdgeInsets.symmetric(horizontal: 6, vertical: 2), width: isDesktop ? 180 : 180, isFocused: _selectedTripType == "2", isDesktop: isDesktop, child: SizedBox( height: 35, child: Material( color: Colors.transparent, child: RadioListTile( activeColor: Colors.blueAccent, contentPadding: EdgeInsets.zero, visualDensity: VisualDensity.compact, dense: true, title: Text("International"), value: "2", groupValue: _selectedTripType, onChanged: (value) { setState(() { _selectedTripType = value!; PolicyName = "International Policy"; SelectedDomestic = "0"; SelectedInternational = "1"; }); }, ), ), ), ), ]; } }