From c61183c472ebb56f66f4a08ba792f3d37fe60a3b Mon Sep 17 00:00:00 2001 From: venbaittech Date: Tue, 10 Jun 2025 13:14:29 +0530 Subject: [PATCH] forex --- lib/Screens/group/group.dart | 527 +++++++++++---------- lib/Screens/itnerary/forex.dart | 58 ++- lib/Screens/itnerary_list/flight_list.dart | 11 +- 3 files changed, 326 insertions(+), 270 deletions(-) diff --git a/lib/Screens/group/group.dart b/lib/Screens/group/group.dart index c0fa831..85ebdf2 100644 --- a/lib/Screens/group/group.dart +++ b/lib/Screens/group/group.dart @@ -93,13 +93,15 @@ class _groupState extends State { String? bodyStringColor = await getBodyColor(); setState(() { - layoutColor = layoutString != null - ? Color(int.parse(layoutString)) - : Colors.redAccent; + layoutColor = + layoutString != null + ? Color(int.parse(layoutString)) + : Colors.redAccent; - bodyColor = bodyStringColor != null - ? Color(int.parse(bodyStringColor)) - : Colors.white; + bodyColor = + bodyStringColor != null + ? Color(int.parse(bodyStringColor)) + : Colors.white; }); } @@ -154,10 +156,7 @@ class _groupState extends State { errorMessages.clear(); // Reset errors // Required fields that must not be empty - List requiredFields = [ - "name", - "description", - ]; + List requiredFields = ["name", "description"]; // Check validation for each field for (String field in requiredFields) { @@ -165,6 +164,14 @@ class _groupState extends State { errorMessages[field] = "Required"; } } + // ✅ At least one of the two policies must be selected + if ((selectedDomestic == null || selectedDomestic!.isEmpty) && + (selectedInternational == null || selectedInternational!.isEmpty)) { + errorMessages["domestic_policy_id"] = "Select at least one policy"; + errorMessages["international_policy_id"] = "Select at least one policy"; + } + + return errorMessages.isEmpty; return errorMessages.isEmpty; // Valid if there are no errors } @@ -223,23 +230,24 @@ class _groupState extends State { } try { - final response = await (isEdit - ? http.put( - Uri.parse(apiUrlData), - headers: { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }, - body: jsonEncode(groupData), - ) - : http.post( - Uri.parse(apiUrlData), - headers: { - 'Authorization': 'Bearer $token', - 'Content-Type': 'application/json', - }, - body: jsonEncode(groupData), - )); + final response = + await (isEdit + ? http.put( + Uri.parse(apiUrlData), + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + body: jsonEncode(groupData), + ) + : http.post( + Uri.parse(apiUrlData), + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + body: jsonEncode(groupData), + )); if (response.statusCode == 200 || response.statusCode == 201) { print("Group submitted successfully!"); @@ -320,32 +328,38 @@ class _groupState extends State { @override Widget build(BuildContext context) { - return ResponsiveBuilder(builder: (context, sizingInfo) { - bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; + return ResponsiveBuilder( + builder: (context, sizingInfo) { + bool isDesktop = + sizingInfo.deviceScreenType == DeviceScreenType.desktop; - return Scaffold( - // backgroundColor: Colors.white, - 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: Row( - children: [ - // if (isDesktop) CustomDrawer(isDesktop: true), - Expanded(child: buildData(isDesktop, context)) - ], + return Scaffold( + // backgroundColor: Colors.white, + 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: Row( + children: [ + // if (isDesktop) CustomDrawer(isDesktop: true), + Expanded(child: buildData(isDesktop, context)), + ], + ), ), - ), - ); - }); + ); + }, + ); } Widget buildData(bool isDesktop, context) { @@ -367,15 +381,16 @@ class _groupState extends State { 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), - ), + child: + isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.end, + children: _buildSubmit(isDesktop), + ) + : Row( + mainAxisAlignment: MainAxisAlignment.center, + children: _buildSubmit(isDesktop), + ), ), ], ), @@ -387,9 +402,10 @@ class _groupState extends State { // 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, + height: + isDesktop + ? MediaQuery.of(context).size.height * 0.98 + : MediaQuery.of(context).size.height, // decoration: BoxDecoration( // border: isDesktop // ? Border.all( @@ -414,10 +430,7 @@ class _groupState extends State { child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Text( - "Create Group", - style: GoogleFonts.poppins(fontSize: 18), - ), + Text("Create Group", style: GoogleFonts.poppins(fontSize: 18)), // Container( // color: Color(0xFFE9EBF6), // child: IconButton( @@ -436,53 +449,52 @@ class _groupState extends State { // height: 5, // ), Container( - margin: const EdgeInsets.all(10), - padding: const EdgeInsets.all(20), - color: Colors.white, - height: MediaQuery.of(context).size.height * 0.6, - child: Column( - children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Text( - // "Mail Settings", - // style: TextStyle(color: Colors.blueAccent), - // ), - // Icon( - // Icons.keyboard_arrow_down_outlined, - // color: Colors.blueAccent, - // size: 30, - // ), - // ], - // ), - isDesktop - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: _buildFirstRow(isDesktop), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: _buildFirstRow(isDesktop), - ), + margin: const EdgeInsets.all(10), + padding: const EdgeInsets.all(20), + color: Colors.white, + height: MediaQuery.of(context).size.height * 0.6, + child: Column( + children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // children: [ + // Text( + // "Mail Settings", + // style: TextStyle(color: Colors.blueAccent), + // ), + // Icon( + // Icons.keyboard_arrow_down_outlined, + // color: Colors.blueAccent, + // size: 30, + // ), + // ], + // ), + isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildFirstRow(isDesktop), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: _buildFirstRow(isDesktop), + ), - SizedBox( - height: 10, - ), + SizedBox(height: 10), - isDesktop - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: _buildSecondRow(isDesktop), - ) - : Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: _buildSecondRow(isDesktop), - ), + isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: _buildSecondRow(isDesktop), + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.center, + children: _buildSecondRow(isDesktop), + ), - // SizedBox(height: 15), - ], - )), + // SizedBox(height: 15), + ], + ), + ), ], ), ); @@ -496,17 +508,19 @@ class _groupState extends State { Text( "Group Name", style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: isDesktop, - width: isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -540,17 +554,19 @@ class _groupState extends State { Text( "Description", style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: isDesktop, - width: isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, child: TextField( @@ -589,72 +605,82 @@ class _groupState extends State { Text( "Select Policy For Domestic", style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: isDesktop, - width: isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, - child: apiForDomestic == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: selectedDomestic == null - ? null - : apiForDomestic! - .firstWhere((policy) => - policy['policy_id'] == - selectedDomestic)['name'] - .toString(), - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Policy...", - contentPadding: - EdgeInsets.symmetric(horizontal: 10), + child: + apiForDomestic == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + selectedDomestic == null + ? null + : apiForDomestic! + .firstWhere( + (policy) => + policy['policy_id'] == + selectedDomestic, + )['name'] + .toString(), + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Policy...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), ), ), - ), - items: apiForDomestic! - .map((policy) => policy['name'].toString()) - .toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + items: + apiForDomestic! + .map((policy) => policy['name'].toString()) + .toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: TextStyle(fontSize: 12), + ), + ), + onChanged: (String? newValue) { + setState(() { + selectedDomestic = + apiForDomestic!.firstWhere( + (policy) => policy['name'] == newValue, + )['policy_id']; + }); + }, ), - dropdownBuilder: (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: TextStyle(fontSize: 12), - ), - ), - onChanged: (String? newValue) { - setState(() { - selectedDomestic = apiForDomestic!.firstWhere( - (policy) => - policy['name'] == newValue)['policy_id']; - }); - }, - ), ), - ) + ), ], ), Column( @@ -663,72 +689,82 @@ class _groupState extends State { Text( "Select Policy For International", style: TextStyle( - fontSize: 12, - fontWeight: FontWeight.w600, - color: Color(0xFF575A74)), + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74), + ), ), SizedBox(height: 5), CustomTextFieldWrapper( isFocused: false, isDesktop: isDesktop, - width: isDesktop - ? MediaQuery.of(context).size.width * 0.34 - : MediaQuery.of(context).size.width * 0.85, + width: + isDesktop + ? MediaQuery.of(context).size.width * 0.34 + : MediaQuery.of(context).size.width * 0.85, child: SizedBox( height: 40, - child: apiForInternational == null - ? Center( - child: Transform.scale( - scale: 0.5, - child: CircularProgressIndicator(), - ), - ) - : DropdownSearch( - selectedItem: selectedInternational == null - ? null - : apiForInternational! - .firstWhere((policy) => - policy['policy_id'] == - selectedInternational)['name'] - .toString(), - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Policy...", - contentPadding: - EdgeInsets.symmetric(horizontal: 10), + child: + apiForInternational == null + ? Center( + child: Transform.scale( + scale: 0.5, + child: CircularProgressIndicator(), + ), + ) + : DropdownSearch( + selectedItem: + selectedInternational == null + ? null + : apiForInternational! + .firstWhere( + (policy) => + policy['policy_id'] == + selectedInternational, + )['name'] + .toString(), + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Policy...", + contentPadding: EdgeInsets.symmetric( + horizontal: 10, + ), + ), ), ), - ), - items: apiForInternational! - .map((policy) => policy['name'].toString()) - .toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 1), + items: + apiForInternational! + .map((policy) => policy['name'].toString()) + .toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select", + style: TextStyle(fontSize: 12), + ), + ), + onChanged: (String? newValue) { + setState(() { + selectedInternational = + apiForInternational!.firstWhere( + (policy) => policy['name'] == newValue, + )['policy_id']; + }); + }, ), - dropdownBuilder: (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select", - style: TextStyle(fontSize: 12), - ), - ), - onChanged: (String? newValue) { - setState(() { - selectedInternational = apiForInternational! - .firstWhere((policy) => - policy['name'] == newValue)['policy_id']; - }); - }, - ), ), - ) + ), ], ), ]; @@ -737,22 +773,21 @@ class _groupState extends State { List _buildSubmit(isDesktop) { return [ ElevatedButton( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: layoutColor, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - side: BorderSide(color: layoutColor ?? Colors.green, width: 2), - ), - padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: layoutColor, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + side: BorderSide(color: layoutColor ?? Colors.green, width: 2), ), - onPressed: () { - context.go('/group'); - }, - child: Text("Cancel")), - SizedBox( - width: 20, + padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), + ), + onPressed: () { + context.go('/group'); + }, + child: Text("Cancel"), ), + SizedBox(width: 20), MouseRegion( // cursor: widget.isViewMode // ? SystemMouseCursors.forbidden @@ -773,7 +808,7 @@ class _groupState extends State { onPressed: handleSubmit, // Disable when in view mode child: Text("Submit"), ), - ) + ), ]; } } diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index efc0c04..1be3cd1 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -53,6 +53,7 @@ class _ForexScreenState extends State { int fifteenPercent = 0; int remainingAmount = 0; + bool isWidget = false; Map focusNodes = {}; Map focusStates = {}; @@ -419,12 +420,16 @@ class _ForexScreenState extends State { selectedCashPercent = int.tryParse( widget.selectedItem!["cash_percentage"]?.toString() ?? "", ); + + print("selectedCashPercentUPdae - $selectedCashPercent"); selectedPerdiemAmount = widget.selectedItem!["perdiem_amount"] as String?; isChecked = widget.selectedItem!["have_card"] == "1"; // Convert string to bool textControllers["_cardNumber"]?.text = widget.selectedItem!["card_number"]?.toString() ?? ""; + isWidget = true; + // if (textControllers["_cardNumber"] != null) { // print("userCardNumber11 - $userCardNumber"); // textControllers["_cardNumber"]!.text = userCardNumber ?? ''; @@ -548,6 +553,13 @@ class _ForexScreenState extends State { selectedQuotedAmount = ((perdiemAmount + calclateVal).toString() ?? 0) as String?; + + if (isWidget) { + print("IsWidget Update"); + + int? quotedAmount = int.tryParse(selectedQuotedAmount!); + fifteenPercent = (quotedAmount! * selectedCashPercent!) ~/ 100; + } }); if (userEdited) { @@ -612,7 +624,8 @@ class _ForexScreenState extends State { ); if (enteredAmount == null || calculateAmnt > qouteAmount!) { - errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount"; + errorMessages["deposit_on_card"] = + "Sum of cash card cannot exceed $qouteAmount"; } else if (checkValidAmount < qouteAmount) { errorMessages["deposit_on_card"] = "Enter Valid Amount"; // Clear error if valid @@ -627,6 +640,7 @@ class _ForexScreenState extends State { void _validateCashAmount(String value) { // errorMessages["deposit_on_card"] = " "; errorMessages.remove("deposit_on_cash"); + print("_validateCashAmount - $value - $fifteenPercent"); int? enteredAmount = int.tryParse(value); @@ -652,6 +666,7 @@ class _ForexScreenState extends State { errorMessages["deposit_on_card"] = "Enter Valid Amount"; // Clear error if valid } + print("CASHfifteenPercent - $fifteenPercent"); errorMessages["deposit_on_cash"] = "Amount cannot exceed $fifteenPercent"; } else if (checkValidAmount == quotedAmount) { errorMessages.remove("deposit_on_cash"); @@ -1204,16 +1219,16 @@ class _ForexScreenState extends State { menuProps: const MenuProps(backgroundColor: Colors.white), itemBuilder: (context, item, isSelected) => Container( - color: Colors.white, - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), - ), - ), + color: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), searchFieldProps: TextFieldProps( decoration: InputDecoration( hintText: "Search ...", @@ -1230,15 +1245,15 @@ class _ForexScreenState extends State { ), dropdownBuilder: (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select ", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select ", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), ), - ), - ), onChanged: (String? newValue) { setState(() { // Find the country_code based on selected country_name @@ -1688,7 +1703,9 @@ class _ForexScreenState extends State { errorMessages.remove("deposit_on_cash"); errorMessages.remove("deposit_on_card"); // errorMessages["deposit_on_card"] = ""; - + setState(() { + userEdited = true; + }); _validateCashAmount( value, ); // Call validation when text changes @@ -1744,6 +1761,7 @@ class _ForexScreenState extends State { onChanged: (value) { errorMessages.remove("deposit_on_cash"); errorMessages.remove("deposit_on_card"); + userEdited = true; _validateCardAmount( value, ); // Call validation when text changes diff --git a/lib/Screens/itnerary_list/flight_list.dart b/lib/Screens/itnerary_list/flight_list.dart index 3d8031d..23cce10 100644 --- a/lib/Screens/itnerary_list/flight_list.dart +++ b/lib/Screens/itnerary_list/flight_list.dart @@ -409,10 +409,13 @@ class _FlightListWidgetState extends State { fontWeight: FontWeight.w700, ), ), - Image.asset( - 'assets/images/IconsImg/alternate.png', - width: 25, - height: 25, + Padding( + padding: const EdgeInsets.only(left: 10), + child: Image.asset( + 'assets/images/IconsImg/alternate.png', + width: 20, + height: 20, + ), ), Text( "$toPlaceCountry",