From 42f3f465d532cf70bf6cec162e81a8bf11d6b35d Mon Sep 17 00:00:00 2001 From: venbaittech Date: Mon, 26 May 2025 10:59:01 +0530 Subject: [PATCH] forex calculations --- .../authentication/login/login_widget.dart | 83 +++-- lib/Screens/department/department_list.dart | 309 +++++++++--------- lib/Screens/forex/forexDetails.dart | 155 ++++++++- lib/Screens/group/groupList.dart | 55 +++- lib/Screens/itnerary/forex.dart | 129 +++++--- lib/Screens/myTemplates/templatesList.dart | 70 ++-- lib/Screens/plans/create_plans.dart | 9 +- .../create_user/traveller_details.dart | 4 +- lib/services/apiService.dart | 45 +++ lib/utils/auth_utils.dart | 5 + 10 files changed, 583 insertions(+), 281 deletions(-) diff --git a/lib/Screens/authentication/login/login_widget.dart b/lib/Screens/authentication/login/login_widget.dart index f6ff2a7..baf9eb2 100644 --- a/lib/Screens/authentication/login/login_widget.dart +++ b/lib/Screens/authentication/login/login_widget.dart @@ -369,7 +369,7 @@ class _LoginWidgetState extends State { ), const SizedBox(height: 2), Text( - "Welcome To Trip Approval Tools", + "Welcome To TripApprovalTool", style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.w400, @@ -822,55 +822,48 @@ class _LoginWidgetState extends State { ); } - Future handleMS() async { + final url = '$apiUrl/auth/mslogin'; + print(url); + try { + final response = await http + .get(Uri.parse(url), headers: {'Content-Type': 'application/json'}); + print("inside try method"); + if (response.statusCode == 200) { + final authUrl = json.decode(response.body)['auth_url']; + print("authurl - $authUrl"); + if (authUrl != '') { + // final prefs = await SharedPreferences.getInstance(); + // await prefs.setString('auth_token', authUrl); + print('i have auth URL'); + // canLaunchUrl(authUrl); - final url = '$apiUrl/auth/mslogin'; - print(url); - try { - final response = await http.get( - Uri.parse(url), - headers: { 'Content-Type': 'application/json' } - ); - print("inside try method"); - if (response.statusCode == 200) { - final authUrl = json.decode(response.body)['auth_url']; - print("authurl - $authUrl"); - if(authUrl != ''){ - // final prefs = await SharedPreferences.getInstance(); - // await prefs.setString('auth_token', authUrl); - print('i have auth URL'); - // canLaunchUrl(authUrl); + if (kIsWeb) { + print("kIsWeb"); + // Use web redirect (e.g., via JS interop or window.location.href) + // redirectTo(url); - if (kIsWeb) { - print("kIsWeb"); - // Use web redirect (e.g., via JS interop or window.location.href) - // redirectTo(url); - - html.window.location.href = authUrl; - } else { - // For mobile/desktop, open in external browser - // launchUrl(Uri.parse(url), - // mode: LaunchMode.externalApplication); - } - // final result = await FlutterWebAuth.authenticate( - // url: authUrl, - // callbackUrlScheme: "myapp", // Use a custom scheme you registered - // ); - }else{ - print('auth URL not Founded'); - throw Exception('auth URL not Founded'); + html.window.location.href = authUrl; + } else { + // For mobile/desktop, open in external browser + // launchUrl(Uri.parse(url), + // mode: LaunchMode.externalApplication); } - }else{ - final errorMessage = json.decode(response.body)['message']; - print(errorMessage); - throw Exception(errorMessage); + // final result = await FlutterWebAuth.authenticate( + // url: authUrl, + // callbackUrlScheme: "myapp", // Use a custom scheme you registered + // ); + } else { + print('auth URL not Founded'); + throw Exception('auth URL not Founded'); } + } else { + final errorMessage = json.decode(response.body)['message']; + print(errorMessage); + throw Exception(errorMessage); } - catch (e) { - print("Error: $e"); - } - + } catch (e) { + print("Error: $e"); + } } - } diff --git a/lib/Screens/department/department_list.dart b/lib/Screens/department/department_list.dart index 9e26f25..51cb4b2 100644 --- a/lib/Screens/department/department_list.dart +++ b/lib/Screens/department/department_list.dart @@ -25,7 +25,7 @@ class DepartmentList extends StatefulWidget { class DepartmentListState extends State { final GlobalKey departmentListKey = - GlobalKey(); + GlobalKey(); final ApiService apiService = ApiService(); late Future> futureDepartment; @@ -97,7 +97,6 @@ class DepartmentListState extends State { } Future> fetchGetDepartment() async { - final String apiUrlData = '$apiUrl/api/getDepartmentList'; final String? token = await getToken(); @@ -142,19 +141,18 @@ class DepartmentListState extends State { print("all before filtering: $query"); final lowerQuery = query.toLowerCase(); setState(() { - filteredDepartment = allDepartment.where((object) { - final isActiveStatus = - object['is_active'] == "1" ? "active" : "inactive"; - return (object['department_id']?.toLowerCase().contains(lowerQuery) ?? - false) || - (object['name']?.toLowerCase().contains(lowerQuery) ?? - false) || - (object['description']?.toLowerCase().contains(lowerQuery) ?? false) || - (isActiveStatus.contains(lowerQuery)); - }).toList(); + filteredDepartment = allDepartment.where((object) { + final isActiveStatus = + object['is_active'] == "1" ? "active" : "inactive"; + return (object['department_id']?.toLowerCase().contains(lowerQuery) ?? + false) || + (object['name']?.toLowerCase().contains(lowerQuery) ?? false) || + (object['description']?.toLowerCase().contains(lowerQuery) ?? + false) || + (isActiveStatus.contains(lowerQuery)); + }).toList(); }); print("filteredDepartment: $filteredDepartment"); - } @override @@ -171,11 +169,11 @@ class DepartmentListState extends State { 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 - ) + 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(0), child: Row( children: [ @@ -297,7 +295,7 @@ class DepartmentListState extends State { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), side: - BorderSide(color: Color(0xFF114D8B), width: 2), + BorderSide(color: Color(0xFF114D8B), width: 2), ), padding: EdgeInsets.symmetric( horizontal: 20, vertical: 12), @@ -317,7 +315,7 @@ class DepartmentListState extends State { }, child: Row( mainAxisSize: - MainAxisSize.min, // Ensures content fits nicely + MainAxisSize.min, // Ensures content fits nicely children: [ Text( "Add Department", @@ -344,46 +342,46 @@ class DepartmentListState extends State { isDesktop ? SizedBox.shrink() : Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - width: MediaQuery.of(context).size.width * 0.8, - height: 35, - child: TextField( - controller: searchController, - onChanged: filterDepartment, - decoration: InputDecoration( - hintText: "Search ...", - hintStyle: TextStyle( - fontSize: 12, color: Color(0xFF9E9DBD)), - prefixIcon: Icon( - Icons.search, - color: Color(0xFF9E9DBD), - size: 18, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Container( + width: MediaQuery.of(context).size.width * 0.8, + height: 35, + child: TextField( + controller: searchController, + onChanged: filterDepartment, + decoration: InputDecoration( + hintText: "Search ...", + hintStyle: TextStyle( + fontSize: 12, color: Color(0xFF9E9DBD)), + prefixIcon: Icon( + Icons.search, + color: Color(0xFF9E9DBD), + size: 18, + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Colors.grey.shade200, + width: 0.5), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + borderSide: BorderSide( + color: Colors.grey.shade300, width: 1), + ), + ), + style: GoogleFonts.poppins( + fontSize: 12, + ), + ), ), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - ), - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: Colors.grey.shade200, - width: 0.5), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(12), - borderSide: BorderSide( - color: Colors.grey.shade300, width: 1), - ), - ), - style: GoogleFonts.poppins( - fontSize: 12, - ), + // SizedBox(width: 16), + ], ), - ), - // SizedBox(width: 16), - ], - ), const SizedBox(height: 10), FutureBuilder>( future: futureDepartment, @@ -432,8 +430,9 @@ class DepartmentListState extends State { ); } /* Here collect the list to displayed the data in table or card Used */ - List object = - filteredDepartment.isNotEmpty ? filteredDepartment : allDepartment; + List object = filteredDepartment.isNotEmpty + ? filteredDepartment + : allDepartment; /* List is Sorting here */ object.sort((a, b) { @@ -454,7 +453,7 @@ class DepartmentListState extends State { Widget table = LayoutBuilder( builder: (context, constraints) { double minWidth = - isDesktop ? constraints.maxWidth : 1300; + isDesktop ? constraints.maxWidth : 1300; return ConstrainedBox( constraints: BoxConstraints(minWidth: minWidth), @@ -468,64 +467,67 @@ class DepartmentListState extends State { columns: [ DataColumn( label: Text( - 'Department ID', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + 'Department ID', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), DataColumn( label: Text( - 'Name', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + 'Name', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), DataColumn( label: Text( - 'Description', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + 'Description', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), DataColumn( label: Text( - 'Status', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + 'Status', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), DataColumn( label: Text( - 'Actions', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + 'Actions', + style: GoogleFonts.poppins( + fontSize: 13, + fontWeight: FontWeight.w600), + )), ], rows: paginatedDepartment.map((tableObject) { - String departmentId = tableObject['department_id'] - .toString(); // Get user ID - bool isSelected = selectedDepartmentId == departmentId; + String departmentId = + tableObject['department_id'] + .toString(); // Get user ID + bool isSelected = + selectedDepartmentId == departmentId; return DataRow(cells: [ - DataCell( - Text("${tableObject['department_id'] ?? ''}", - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", - ))), + DataCell(Text( + "${tableObject['department_id'] ?? ''}", + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ))), DataCell(Text(tableObject['name'] ?? '', style: TextStyle( fontSize: 13, fontFamily: "Inter", ))), - DataCell(Text(tableObject['description'] ?? 'N/A', - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", - ), - softWrap: true, - overflow: TextOverflow.ellipsis)), + DataCell( + Text(tableObject['description'] ?? 'N/A', + style: TextStyle( + fontSize: 13, + fontFamily: "Inter", + ), + softWrap: true, + overflow: TextOverflow.ellipsis)), DataCell( Text( tableObject['is_active'] == "1" @@ -534,7 +536,9 @@ class DepartmentListState extends State { style: TextStyle( fontSize: 13, fontFamily: "Inter", - color: tableObject['is_active'] == "1" ? Colors.green : Colors.red, + color: tableObject['is_active'] == "1" + ? Colors.green + : Colors.red, ), softWrap: true, overflow: TextOverflow.ellipsis, @@ -558,17 +562,21 @@ class DepartmentListState extends State { final departmentId = int.tryParse( tableObject['department_id'] .toString()); - if (departmentId != null) { - print("Table cell - department Id -- $departmentId"); - final data = await apiService.getDepartmentDetailsFind(departmentId); + print( + "Table cell - department Id -- $departmentId"); + final data = await apiService + .getDepartmentDetailsFind( + departmentId); print("DepartmentId -- $data"); showDialog( context: context, - builder: (context) => DepartmentData( + builder: (context) => + DepartmentData( isDesktop: isDesktop, - departmentId: departmentId, // Pass the ID + departmentId: + departmentId, // Pass the ID departmentData: data, layoutColor: layoutColor!, // fetchGetForex: fetchGetForex, @@ -612,7 +620,7 @@ class DepartmentListState extends State { // Status and Employee Code Row( mainAxisAlignment: - MainAxisAlignment.spaceBetween, + MainAxisAlignment.spaceBetween, children: [ Text( cardObject['department_id'] ?? 'N/A', @@ -636,20 +644,25 @@ class DepartmentListState extends State { .toString()); if (departmentId != null) { - print("departmentId -- $departmentId"); + print( + "departmentId -- $departmentId"); final data = await apiService - .getDepartmentDetailsFind(departmentId); + .getDepartmentDetailsFind( + departmentId); print("DepartmentId -- $data"); showDialog( context: context, - builder: (context) => DepartmentData( + builder: (context) => + DepartmentData( isDesktop: isDesktop, - departmentId:departmentId, // Pass the ID - departmentData:data, - layoutColor:layoutColor!, + departmentId: + departmentId, // Pass the ID + departmentData: data, + layoutColor: layoutColor!, // fetchGetDepartment: fetchGetDepartment, - fetchGetDepartment: refreshData, + fetchGetDepartment: + refreshData, // role: // "Travel Agent" ), @@ -742,7 +755,7 @@ class DepartmentListState extends State { children: [ Column( crossAxisAlignment: - CrossAxisAlignment.start, + CrossAxisAlignment.start, children: [ Text( cardObject['name'] ?? '', @@ -757,7 +770,7 @@ class DepartmentListState extends State { ), Column( crossAxisAlignment: - CrossAxisAlignment.start, + CrossAxisAlignment.start, children: [ Text( cardObject['description'] ?? '', @@ -779,39 +792,39 @@ class DepartmentListState extends State { ); } - return Expanded( child: Column( // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Expanded( - child: isDesktop - ? (searchController.text.isNotEmpty && - filteredDepartment.isEmpty - ? Center( - child: Text( - "No matches found", - style: GoogleFonts.poppins( - fontSize: 14, - color: Colors.grey), - ), - ) - : SingleChildScrollView( - scrollDirection: Axis.vertical, - child: table, - )) - : (searchController.text.isNotEmpty && - filteredDepartment.isEmpty - ? Center( - child: Text( - "No matches found", - style: GoogleFonts.poppins( - fontSize: 14, - color: Colors.grey), - ), - ) - : buildMobileCardView(paginatedDepartment)), - ), + Expanded( + child: isDesktop + ? (searchController.text.isNotEmpty && + filteredDepartment.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : SingleChildScrollView( + scrollDirection: Axis.vertical, + child: table, + )) + : (searchController.text.isNotEmpty && + filteredDepartment.isEmpty + ? Center( + child: Text( + "No matches found", + style: GoogleFonts.poppins( + fontSize: 14, + color: Colors.grey), + ), + ) + : buildMobileCardView( + paginatedDepartment)), + ), // Expanded( // child: isDesktop // ? SingleChildScrollView( @@ -846,4 +859,4 @@ class DepartmentListState extends State { )), ); } -} \ No newline at end of file +} diff --git a/lib/Screens/forex/forexDetails.dart b/lib/Screens/forex/forexDetails.dart index 0291648..5a26363 100644 --- a/lib/Screens/forex/forexDetails.dart +++ b/lib/Screens/forex/forexDetails.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:dropdown_search/dropdown_search.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; @@ -51,11 +52,16 @@ class ForexDataState extends State { int? forexDataId; late String isActive = "1"; + bool isCashEditing = false; + bool isCardEditing = false; + List dataHeader = [ "country_code", "country", "currency", - "perdiemAmount" + "perdiemAmount", + "cash", + "card" ]; Map forex_Detials() { @@ -64,6 +70,8 @@ class ForexDataState extends State { "country_code": selectedCountry, "country_name": selectedCountryName, "currency": controllers["currency"]?.text, + "cash_percentage": controllers["cash"]?.text, + "card_percentage": controllers["card"]?.text, "perdiem_amount": controllers["perdiemAmount"]?.text, "is_active": 1, "created_by": userId, @@ -82,6 +90,10 @@ class ForexDataState extends State { controllers[field] = TextEditingController(); } fetchCountries(); + + controllers["cash"]?.addListener(_handleCashChange); + controllers["card"]?.addListener(_handleCardChange); + if (widget.forexId != null) { print('Editing Forex ID: ${widget.forexId}'); updateForexDetails(); @@ -116,6 +128,8 @@ class ForexDataState extends State { selectedCurrency = data['currency']; // Optional if used elsewhere controllers['currency']?.text = data['currency'] ?? ''; + controllers['cash']?.text = data['cash_percentage'] ?? ''; + controllers['card']?.text = data['card_percentage'] ?? ''; controllers['perdiemAmount']?.text = data['perdiem_amount'].toString(); isActive = data["is_active"]; final forexId = int.tryParse(data['forex_perdiem_id'].toString()); @@ -140,6 +154,31 @@ class ForexDataState extends State { }); } + void _handleCashChange() { + if (isCardEditing) return; // Prevent circular update + + isCashEditing = true; + final cashText = controllers["cash"]?.text ?? ''; + final cash = int.tryParse(cashText) ?? 0; + + final card = 100 - cash; + controllers["card"]?.text = card.toString(); + isCashEditing = false; + } + + void _handleCardChange() { + if (isCashEditing) return; // Prevent circular update + + final cash = int.tryParse(controllers["cash"]?.text ?? '') ?? 0; + final card = int.tryParse(controllers["card"]?.text ?? '') ?? 0; + + if (cash + card != 100) { + errorMessages["cash_percentage"] = "Cash and card must total 100%"; + } else { + errorMessages.remove("cash_percentage"); + } + } + bool validateData() { errorMessages.clear(); @@ -147,6 +186,8 @@ class ForexDataState extends State { "country_code": selectedCountry, "country": selectedCountryName, "currency": controllers["currency"]?.text, + "cash_percentage": controllers["cash"]?.text, + "card_percentage": controllers["card"]?.text, "perdiemAmount": controllers["perdiemAmount"]?.text, }; @@ -154,7 +195,9 @@ class ForexDataState extends State { "country_code", "country", "currency", - "perdiemAmount" + "perdiemAmount", + "cash_percentage", + "card_percentage" ]; // Check validation for each field @@ -164,6 +207,13 @@ class ForexDataState extends State { } } + final cash = int.tryParse(data["cash_percentage"] ?? '') ?? 0; + final card = int.tryParse(data["card_percentage"] ?? '') ?? 0; + + if (cash + card != 100) { + errorMessages["card_percentage"] = "Total must be 100%"; + } + return errorMessages.isEmpty; } @@ -431,6 +481,107 @@ class ForexDataState extends State { ), // if (isDesktop)SizedBox(width: 8,) else SizedBox(height: 8,), + SizedBox( + height: 10, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Cash", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74)), + ), + SizedBox(height: 5), + CustomTextFieldForexWrapper( + isFocused: false, + isDesktop: widget.isDesktop, + color: Colors.transparent, + width: widget.isDesktop + ? MediaQuery.of(context).size.width * 0.09 + : MediaQuery.of(context).size.width * 0.66, + child: SizedBox( + height: 40, + child: TextField( + controller: controllers["cash"], + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Cash", + labelStyle: + TextStyle(fontSize: 11, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + ), + )), + ), + if (errorMessages["cash_percentage"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["cash_percentage"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ), + Spacer(), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Card", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, + color: Color(0xFF575A74)), + ), + SizedBox(height: 5), + CustomTextFieldForexWrapper( + isFocused: false, + isDesktop: widget.isDesktop, + color: Colors.transparent, + width: widget.isDesktop + ? MediaQuery.of(context).size.width * 0.09 + : MediaQuery.of(context).size.width * 0.66, + child: SizedBox( + height: 40, + child: TextField( + controller: controllers["card"], + keyboardType: TextInputType.number, + inputFormatters: [ + FilteringTextInputFormatter.digitsOnly, + ], + style: const TextStyle(fontSize: 12), + decoration: const InputDecoration( + labelText: "Card", + labelStyle: + TextStyle(fontSize: 11, color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + ), + )), + ), + if (errorMessages["card_percentage"] != null) ...[ + SizedBox(height: 5), // Space before error message + Text( + errorMessages["card_percentage"]!, + style: TextStyle(color: Colors.red, fontSize: 12), + ), + ], + ], + ) + ], + ), SizedBox( height: 10, ), diff --git a/lib/Screens/group/groupList.dart b/lib/Screens/group/groupList.dart index 086387d..38c0875 100644 --- a/lib/Screens/group/groupList.dart +++ b/lib/Screens/group/groupList.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:frontend/Screens/group/group.dart'; import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:responsive_builder/responsive_builder.dart'; @@ -209,9 +210,14 @@ class _GroupListState extends State { children: [ Row( children: [ - const Text('Group List', - style: - TextStyle(fontSize: 18, fontWeight: FontWeight.bold)), + Text( + 'Group List', + style: GoogleFonts.poppins( + fontSize: isDesktop ? 16 : 14, + fontWeight: FontWeight.w600, + color: Colors.black, + ), + ), IconButton( icon: const Icon(Icons.keyboard_arrow_down), onPressed: () {}, @@ -234,7 +240,7 @@ class _GroupListState extends State { }, child: Row( children: [ - Text('New Group'), + Text('New Group', style: GoogleFonts.poppins(fontSize: 12)), SizedBox( width: 5, ), @@ -300,9 +306,24 @@ class _GroupListState extends State { Row( children: [ Expanded( - child: Text("Group Name: ${group['name']}", - style: TextStyle( - fontSize: 13, fontWeight: FontWeight.bold)), + child: Text("Group Name", + style: GoogleFonts.poppins( + fontSize: 11.5, fontWeight: FontWeight.w400)), + ), + Expanded( + child: Text("Domestic Policy", + style: GoogleFonts.poppins( + fontSize: 11.5, fontWeight: FontWeight.w400)), + ), + Expanded( + child: Text("International Policy", + style: GoogleFonts.poppins( + fontSize: 11.5, fontWeight: FontWeight.w400)), + ), + Expanded( + child: Text("Description", + style: GoogleFonts.poppins( + fontSize: 11.5, fontWeight: FontWeight.w400)), ), ], ), @@ -311,9 +332,23 @@ class _GroupListState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( - child: Text( - "Policy: ${group['domestic_policy_name'] ?? group['international_policy_name']}")), - Expanded(child: Text("${group['description'] ?? 'N/A'}")), + child: Text("${group['name']}", + style: GoogleFonts.poppins( + fontSize: 13, fontWeight: FontWeight.w600)), + ), + Expanded( + child: Text("${group['domestic_policy_name'] ?? 'N/A'}", + style: GoogleFonts.poppins( + fontSize: 13, fontWeight: FontWeight.w600)), + ), + Expanded( + child: Text("${group['international_policy_name']}", + style: GoogleFonts.poppins( + fontSize: 13, fontWeight: FontWeight.w600))), + Expanded( + child: Text("${group['description'] ?? 'N/A'}", + style: GoogleFonts.poppins( + fontSize: 13, fontWeight: FontWeight.w600))), ], ), Row( diff --git a/lib/Screens/itnerary/forex.dart b/lib/Screens/itnerary/forex.dart index c52ab0d..1368b1b 100644 --- a/lib/Screens/itnerary/forex.dart +++ b/lib/Screens/itnerary/forex.dart @@ -42,8 +42,10 @@ class _ForexScreenState extends State { late ValueNotifier flightFirstTripDateNotifier; late ValueNotifier flightLastTripDateNotifier; + // late final tripuserId; + String? tripuserId; - late String? userCardNumber; + // late String? userCardNumber; Map selectedValues = {}; bool isChecked = false; // State variable for checkbox @@ -97,6 +99,10 @@ class _ForexScreenState extends State { String? selectedPerdiemAmount; String? CalculatedOtherExpenses; String? selectedQuotedAmount; + int? selectedCashPercent; + int? selectedCardPercent; + + bool userEdited = false; Map get forexData { Map data = { @@ -116,6 +122,8 @@ class _ForexScreenState extends State { "delivery_location": textControllers["_deliveryLocation"]?.text, "comments": textControllers["_comments"]?.text, "total": selectedQuotedAmount, + "card_percentage": selectedCardPercent, + "cash_percentage": selectedCashPercent, "created_by": widget.loginUser, "updated_by": widget.loginUser, }; @@ -138,6 +146,7 @@ class _ForexScreenState extends State { "country_code": selectedCountry, "start_date": _formatDate(textControllers["_forexStartDate"]?.text), "end_date": _formatDate(textControllers["_forexEndDate"]?.text), + "user_id": tripuserId // "currency": selectedCurrency ?? "", }; } @@ -186,6 +195,13 @@ class _ForexScreenState extends State { selectedDuration = responseData["duration"]?.toString() ?? ""; selectedQuotedAmount = responseData["perdiem_amount"]?.toString() ?? ""; + selectedCardPercent = + int.tryParse(responseData["card_percentage"]?.toString() ?? ""); + selectedCashPercent = + int.tryParse(responseData["cash_percentage"]?.toString() ?? ""); + + textControllers["_cardNumber"]?.text = + responseData["forex_card_no"]?.toString() ?? ""; }); _onFieldChangedForOthers(); _divideQuotedAmount(); @@ -325,7 +341,10 @@ class _ForexScreenState extends State { flightFirstTripDateNotifier = ValueNotifier(null); flightLastTripDateNotifier = ValueNotifier(null); - WidgetsBinding.instance.addPostFrameCallback((_) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + tripuserId = await getTripUserId(); + + print("tripuserId - $tripuserId"); final result = getFlightTripDateRange(widget.flightData); flightFirstTripDateNotifier.value = result['firstTripDate']; flightLastTripDateNotifier.value = result['lastTripDate']; @@ -351,15 +370,15 @@ class _ForexScreenState extends State { void handleUpdatedField() async { // Set the selected value if available - - userCardNumber = await getForexCardNumber(); - // userCardNumber = "CD7909043"; - print("userCardNumber - $userCardNumber"); + // + // userCardNumber = await getForexCardNumber(); + // // userCardNumber = "CD7909043"; + // print("userCardNumber - $userCardNumber"); if (widget.selectedItem == null && textControllers["_cardNumber"]?.text == "") { - print("userCardNumber11 - $userCardNumber"); - textControllers["_cardNumber"]?.text = userCardNumber ?? ""; + // print("userCardNumber11 - $userCardNumber"); + // textControllers["_cardNumber"]?.text = userCardNumber ?? ""; } if (widget.selectedItem != null) { @@ -381,13 +400,20 @@ class _ForexScreenState extends State { selectedCountry = widget.selectedItem!["country_code"] as String?; selectedCurrency = widget.selectedItem!["currency"] as String?; selectedDuration = widget.selectedItem!["duration"] as String?; + selectedCardPercent = int.tryParse( + widget.selectedItem!["card_percentage"]?.toString() ?? ""); + selectedCashPercent = int.tryParse( + widget.selectedItem!["cash_percentage"]?.toString() ?? ""); 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() ?? ""; // if (textControllers["_cardNumber"] != null) { // print("userCardNumber11 - $userCardNumber"); // textControllers["_cardNumber"]!.text = userCardNumber ?? ''; + // // } _onFieldChangedForOthers(); @@ -431,7 +457,11 @@ class _ForexScreenState extends State { } if (_isForexDataComplete()) { - postgetForexData(getForexData); + if (tripuserId != null) { + postgetForexData(getForexData); + } else { + print("tripuserId is null"); + } } } @@ -503,35 +533,42 @@ class _ForexScreenState extends State { selectedQuotedAmount = ((perdiemAmount + calclateVal).toString() ?? 0) as String?; }); - _divideQuotedAmount(); + + if (userEdited) { + _divideQuotedAmount(); + } errorMessages.clear(); } void _divideQuotedAmount() { int? quotedAmount = int.tryParse(selectedQuotedAmount!); + print("quotedAmount - $selectedQuotedAmount"); + print("DIVIDREFD - $selectedQuotedAmount -$quotedAmount"); if (quotedAmount != null) { - fifteenPercent = - (quotedAmount * 15) ~/ 100; // Calculate 15% (integer division) + // fifteenPercent = (quotedAmount * 15) ~/ 100; + print("selectedCardPercent - $selectedCashPercent"); + fifteenPercent = (quotedAmount * selectedCashPercent!) ~/ + 100; // Calculate 15% (integer division) remainingAmount = quotedAmount - fifteenPercent; // Subtract from total - // Only set text if the field is empty (user hasn't typed) - if (textControllers["_cash"] != null && - textControllers["_cash"]!.text.trim().isEmpty) { - textControllers["_cash"]!.text = fifteenPercent.toString(); - } else { - print("_cash already has user input, not overwriting"); - } + // // Only set text if the field is empty (user hasn't typed) + // if (textControllers["_cash"] != null && + // textControllers["_cash"]!.text.trim().isEmpty) { + // textControllers["_cash"]!.text = fifteenPercent.toString(); + // } else { + // print("_cash already has user input, not overwriting"); + // } + // + // if (textControllers["_card"] != null && + // textControllers["_card"]!.text.trim().isEmpty) { + // textControllers["_card"]!.text = remainingAmount.toString(); + // } else { + // print("_card already has user input, not overwriting"); + // } - if (textControllers["_card"] != null && - textControllers["_card"]!.text.trim().isEmpty) { - textControllers["_card"]!.text = remainingAmount.toString(); - } else { - print("_card already has user input, not overwriting"); - } - - // textControllers["_cash"]?.text = fifteenPercent.toString(); - // textControllers["_card"]?.text = remainingAmount.toString(); + textControllers["_cash"]?.text = fifteenPercent.toString(); + textControllers["_card"]?.text = remainingAmount.toString(); print("15% Amount: $fifteenPercent"); print("Remaining Amount: $remainingAmount"); } else { @@ -588,13 +625,13 @@ class _ForexScreenState extends State { print('CardAmount - $cardAmount'); textControllers["_card"]?.text = difference.toString(); - if (enteredAmount == null || enteredAmount > fifteenPercent) { - errorMessages["deposit_on_cash"] = "Amount cannot exceed $fifteenPercent"; - } else if (checkValidAmount == quotedAmount) { - errorMessages["deposit_on_card"] = " "; // Clear error if valid - } else { - errorMessages["deposit_on_cash"] = ""; // Clear error if valid - } + // if (enteredAmount > fifteenPercent) { + // errorMessages["deposit_on_cash"] = "Amount cannot exceed $fifteenPercent"; + // } else if (checkValidAmount == quotedAmount) { + // errorMessages["deposit_on_card"] = " "; // Clear error if valid + // } else { + // errorMessages["deposit_on_cash"] = ""; // Clear error if valid + // } // Refresh UI if using StatefulWidget setState(() {}); @@ -1253,7 +1290,12 @@ class _ForexScreenState extends State { child: TextField( focusNode: focusNodes["_transport"], controller: textControllers["_transport"], - onChanged: (value) => _onFieldChangedForOthers(), + onChanged: (value) { + setState(() { + userEdited = true; + }); + _onFieldChangedForOthers(); + }, keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp( @@ -1324,7 +1366,12 @@ class _ForexScreenState extends State { child: TextField( focusNode: focusNodes["_accomodation"], controller: textControllers["_accomodation"], - onChanged: (value) => _onFieldChangedForOthers(), + onChanged: (value) { + setState(() { + userEdited = true; + }); + _onFieldChangedForOthers(); + }, keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp( @@ -1396,7 +1443,12 @@ class _ForexScreenState extends State { child: TextField( focusNode: focusNodes["_telephone"], controller: textControllers["_telephone"], - onChanged: (value) => _onFieldChangedForOthers(), + onChanged: (value) { + setState(() { + userEdited = true; + }); + _onFieldChangedForOthers(); + }, keyboardType: TextInputType.numberWithOptions(decimal: true), inputFormatters: [ FilteringTextInputFormatter.allow(RegExp( @@ -1536,6 +1588,7 @@ class _ForexScreenState extends State { style: const TextStyle(fontSize: 12), keyboardType: TextInputType.number, onChanged: (value) { + // errorMessages["deposit_on_cash"] = ""; _validateCashAmount( value); // Call validation when text changes }, diff --git a/lib/Screens/myTemplates/templatesList.dart b/lib/Screens/myTemplates/templatesList.dart index f5b5e66..67f5903 100644 --- a/lib/Screens/myTemplates/templatesList.dart +++ b/lib/Screens/myTemplates/templatesList.dart @@ -610,13 +610,13 @@ class TemplatesListState extends State { fontSize: 13, fontWeight: FontWeight.w600), )), - DataColumn( - label: Text( - 'Attributes', - style: GoogleFonts.poppins( - fontSize: 13, - fontWeight: FontWeight.w600), - )), + // DataColumn( + // label: Text( + // 'Attributes', + // style: GoogleFonts.poppins( + // fontSize: 13, + // fontWeight: FontWeight.w600), + // )), DataColumn( label: Text( 'Actions', @@ -640,12 +640,12 @@ class TemplatesListState extends State { fontSize: 13, fontFamily: "Inter", ))), - DataCell(Text( - getPlaceholderNames(forex['placeholder']), - style: TextStyle( - fontSize: 13, - fontFamily: "Inter", - ))), + // DataCell(Text( + // getPlaceholderNames(forex['placeholder']), + // style: TextStyle( + // fontSize: 13, + // fontFamily: "Inter", + // ))), DataCell( // UserActionsMenu( // user: forex, @@ -661,14 +661,14 @@ class TemplatesListState extends State { // final userId = getUserId(user['user_id']); // final usersData = await getUserDetails(userId); // - final forexId = int.tryParse( + final templateId = int.tryParse( forex['forex_perdiem_id'] .toString()); - if (forexId != null) { - print("ForexId -- $forexId"); + if (templateId != null) { + print("templateId -- $templateId"); final data = await apiService - .getForexDetailsFind(forexId); + .getTemplateFind(templateId); print("ForexId -- $data"); } else { print("Invalid Forex ID"); @@ -725,24 +725,24 @@ class TemplatesListState extends State { SizedBox(height: 2), // Trip Id and Trip Name - Row( - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - getPlaceholderNames( - forex['placeholder']), - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black87, - fontWeight: FontWeight.w500), - ), - ], - ), - ], - ), + // Row( + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // getPlaceholderNames( + // forex['placeholder']), + // style: GoogleFonts.poppins( + // fontSize: 12, + // color: Colors.black87, + // fontWeight: FontWeight.w500), + // ), + // ], + // ), + // ], + // ), // Actions // Actions diff --git a/lib/Screens/plans/create_plans.dart b/lib/Screens/plans/create_plans.dart index 69fb7e1..52ee358 100644 --- a/lib/Screens/plans/create_plans.dart +++ b/lib/Screens/plans/create_plans.dart @@ -680,7 +680,8 @@ class CreateNewPlansState extends State { } } - void getSelectedPlanFor() { + Future getSelectedPlanFor() async { + var userTripId; // if (!mounted) return; print("getSelectedPlanFor"); setState(() { @@ -689,18 +690,24 @@ class CreateNewPlansState extends State { if (selectedIstravelUser!) { planUsrId = ""; planTravlrId = selectedplanUserId; + userTripId = selectedplanUserId; } else { planUsrId = selectedplanUserId; planTravlrId = ""; + userTripId = selectedplanUserId; } } else { print("Is USER ID - $planUsrId "); planUsrId = selfId; planTravlrId = ""; _selectedOption = "Option 1"; + userTripId = selfId; } }); + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('trip_planned_user', userTripId); + print("USER ID - $planUsrId , TRAVELLER ID - $planTravlrId"); } diff --git a/lib/Screens/userManagement/create_user/traveller_details.dart b/lib/Screens/userManagement/create_user/traveller_details.dart index 3d4a880..4ff5d0d 100644 --- a/lib/Screens/userManagement/create_user/traveller_details.dart +++ b/lib/Screens/userManagement/create_user/traveller_details.dart @@ -2416,7 +2416,7 @@ class TravellerDetailsState extends State { ), searchFieldProps: TextFieldProps( decoration: InputDecoration( - hintText: "Search Country...", + hintText: "Search Airline...", hintStyle: GoogleFonts.poppins(fontSize: 11.5), contentPadding: EdgeInsets.symmetric(horizontal: 10), ), @@ -2435,7 +2435,7 @@ class TravellerDetailsState extends State { // Center-align selected item alignment: Alignment.centerLeft, child: Text( - selectedItem ?? "Select Country", + selectedItem ?? "Select Airline", style: TextStyle(fontSize: 12), ), ), diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index 2640fd3..11ca1d1 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -887,6 +887,51 @@ class ApiService { } } + Future> getTemplateFind(int id) async { + final String apiUrldata = '$apiUrl/api/template/find/$id'; + + final token = await getToken(); + + if (token == null) { + throw Exception('Token not found. Please log in.'); + } + + final response = await http.get( + Uri.parse(apiUrldata), + headers: { + 'Authorization': 'Bearer $token', + 'Content-Type': 'application/json', + }, + ); + + if (response.statusCode == 200) { + try { + final data = json.decode(response.body); + // print('findout the result'); + // print(data.runtimeType); + // print(data); + + if (!data.containsKey('data') || data['data'] is! List) { + throw Exception( + "Invalid response format: 'data' field is missing or not a List"); + } + + final List> listData = + List>.from(data['data']); + + if (listData.isEmpty) { + throw Exception("No department found with ID $id"); + } + + return listData[0]; + } catch (e) { + throw Exception('Error parsing response: $e'); + } + } else { + throw Exception('Failed to load department details'); + } + } + Future showCancelConfirmationDialog( BuildContext context, Color? layoutColor) async { return await showDialog( diff --git a/lib/utils/auth_utils.dart b/lib/utils/auth_utils.dart index ebc01f6..83ba0e6 100644 --- a/lib/utils/auth_utils.dart +++ b/lib/utils/auth_utils.dart @@ -7,6 +7,11 @@ Future getToken() async { return prefs.getString("auth_token"); } +Future getTripUserId() async { + final prefs = await SharedPreferences.getInstance(); + return prefs.getString("trip_planned_user"); +} + Future getLayoutColor() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString("layout_color");