From b55b908f42badb886b8bfdb718350ee38ff23321 Mon Sep 17 00:00:00 2001 From: venbaittech Date: Mon, 19 May 2025 11:21:20 +0530 Subject: [PATCH] userManagement changes ,profile highlighter --- lib/Screens/approvals/approval_list.dart | 2 +- .../authentication/login/login_widget.dart | 176 +++---- lib/Screens/group/group.dart | 3 +- lib/Screens/organization/mailSettings.dart | 46 +- lib/Screens/organization/orgSetup.dart | 212 ++++----- lib/Screens/plans/list_plans.dart | 11 +- .../create_user/create_user.dart | 36 +- .../create_user/personal_details.dart | 37 +- .../create_user/traveller_details.dart | 438 ++++++++++++++---- lib/routes/custom_appBar.dart | 406 +++++++--------- lib/routes/custom_drawer.dart | 6 +- lib/routes/custom_router.dart | 4 + lib/services/apiService.dart | 4 +- 13 files changed, 842 insertions(+), 539 deletions(-) diff --git a/lib/Screens/approvals/approval_list.dart b/lib/Screens/approvals/approval_list.dart index a6d84a6..e2afbbf 100644 --- a/lib/Screens/approvals/approval_list.dart +++ b/lib/Screens/approvals/approval_list.dart @@ -403,7 +403,7 @@ class _ApprovalListState extends State { ), if (isDesktop) SizedBox( - width: MediaQuery.of(context).size.width * 0.19, + width: MediaQuery.of(context).size.width * 0.23, ), if (isDesktop) diff --git a/lib/Screens/authentication/login/login_widget.dart b/lib/Screens/authentication/login/login_widget.dart index 2a38b92..e5d4677 100644 --- a/lib/Screens/authentication/login/login_widget.dart +++ b/lib/Screens/authentication/login/login_widget.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:fluttertoast/fluttertoast.dart'; import 'package:frontend/config/apiUrl.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:go_router/go_router.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -258,7 +259,8 @@ class _LoginWidgetState extends State { return Container( // color: Color(0xFF114D8B), color: Color(0xFFf5f5f5), - padding: const EdgeInsets.all(20), + + padding: const EdgeInsets.all(10), child: Row( children: [ if (widget.isDesktop) @@ -266,34 +268,58 @@ class _LoginWidgetState extends State { flex: 2, child: Container( decoration: BoxDecoration( - image: DecorationImage( - image: AssetImage( - 'assets/images/login/login_travel.png', - ), - - // fit: BoxFit.fill - // fit: BoxFit.contain - // fit: BoxFit.cover, // or BoxFit.contain, BoxFit.fill, etc. - ), - color: Colors.white, + // image: DecorationImage( + // image: AssetImage( + // 'assets/images/login/login_travel.png', + // ), + // // fit: BoxFit.fill + // fit: BoxFit.contain + // // fit: BoxFit.cover, // or BoxFit.contain, BoxFit.fill, etc. + // ), + color: Color(0xFFE6F0FA), + // color: Color(0xFFF0F7FF), + // color: Colors.white, borderRadius: BorderRadius.only( - topRight: Radius.circular(25), // Rounded top-left corner + topRight: Radius.circular(250), // Rounded top-left corner bottomRight: - Radius.circular(25), // Rounded bottom-left corner + Radius.circular(250), // Rounded bottom-left corner ), ), - child: Padding( - padding: const EdgeInsets.only( - left: 0, - ), - child: Align( - alignment: Alignment.topLeft, - child: Image.asset( - 'assets/images/login/logoNew.jpg', - width: 200, // Optional: control size - height: 100, - fit: BoxFit.contain, - )), + // child: Padding( + // padding: const EdgeInsets.only( + // left: 0, + // ), + // child: Align( + // alignment: Alignment.topLeft, + // child: Image.asset( + // 'assets/images/login/logoNew.jpg', + // width: 200, // Optional: control size + // height: 100, + // fit: BoxFit.contain, + // )), + // ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Image.asset( + 'assets/images/login/logoNew.jpg', + width: 200, // Optional: control size + height: 100, + fit: BoxFit.contain, + ), + Expanded( + child: Container( + child: Align( + // alignment: Alignment.bottomRight, + child: Image.asset( + 'assets/images/login/login_travel.png', + // width: 200, // Optional: control size + // height: 100, + fit: BoxFit.contain, + )), + ), + ) + ], ), ), ), @@ -301,7 +327,8 @@ class _LoginWidgetState extends State { flex: 1, child: Container( decoration: BoxDecoration( - color: Colors.white, + // color: Colors.white, + borderRadius: BorderRadius.only( topLeft: Radius.circular(25), // Rounded top-left corner bottomLeft: Radius.circular(25), // Rounded bottom-left corner @@ -329,20 +356,18 @@ class _LoginWidgetState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - const Text( + Text( "Sign In", - style: TextStyle( - fontSize: 26, - fontFamily: "Nunito", - fontWeight: FontWeight.w600, + style: GoogleFonts.poppins( + fontSize: 18, + fontWeight: FontWeight.w500, color: Color(0xFF212121)), ), const SizedBox(height: 2), - const Text( + Text( "Welcome To TravelSpends", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 11, - fontFamily: "Nunito", fontWeight: FontWeight.w400, color: Color(0xFF212121)), ), @@ -353,10 +378,8 @@ class _LoginWidgetState extends State { _buildLabel("Email Address"), TextFormField( controller: _emailController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), decoration: _inputDecoration("Enter your email address").copyWith( prefixIcon: Icon( @@ -374,10 +397,8 @@ class _LoginWidgetState extends State { _buildLabel("Password"), TextFormField( controller: _passwordController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), obscureText: _obscureText, decoration: _inputDecoration("Enter your password").copyWith( prefixIcon: Icon( @@ -422,10 +443,8 @@ class _LoginWidgetState extends State { children: [ Text( "Sign In", - style: TextStyle( - fontFamily: "Nunito", - fontWeight: FontWeight.w800, - fontSize: 15), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w800, fontSize: 15), ), SizedBox( width: 3, @@ -445,10 +464,8 @@ class _LoginWidgetState extends State { _buildLabel("Email Address"), TextFormField( controller: _emailController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), decoration: _inputDecoration("Enter your email address").copyWith( prefixIcon: Icon( @@ -481,10 +498,8 @@ class _LoginWidgetState extends State { children: [ Text( "Submit", - style: TextStyle( - fontFamily: "Nunito", - fontWeight: FontWeight.w800, - fontSize: 15), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w800, fontSize: 15), ), SizedBox( width: 3, @@ -505,10 +520,8 @@ class _LoginWidgetState extends State { TextFormField( controller: _emailController, readOnly: true, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), decoration: _inputDecoration("Enter your email address").copyWith( prefixIcon: Icon( @@ -523,10 +536,8 @@ class _LoginWidgetState extends State { _buildLabel("OTP"), TextFormField( controller: _otpController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), decoration: _inputDecoration("Enter your OTP").copyWith( prefixIcon: Icon( Icons.email_outlined, @@ -540,10 +551,8 @@ class _LoginWidgetState extends State { _buildLabel("New Password"), TextFormField( controller: _newPasswordController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), obscureText: _obscureText, decoration: _inputDecoration("Enter your new password").copyWith( @@ -569,10 +578,8 @@ class _LoginWidgetState extends State { _buildLabel("Confirm Password"), TextFormField( controller: _confirmPasswordController, - style: TextStyle( - fontFamily: "Archivo", - fontWeight: FontWeight.w600, - fontSize: 11), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w600, fontSize: 11), obscureText: _obscureText, decoration: _inputDecoration("Enter your confirm password").copyWith( @@ -630,10 +637,8 @@ class _LoginWidgetState extends State { children: [ Text( "Submit", - style: TextStyle( - fontFamily: "Nunito", - fontWeight: FontWeight.w800, - fontSize: 15), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w800, fontSize: 15), ), SizedBox( width: 3, @@ -663,10 +668,10 @@ class _LoginWidgetState extends State { }, child: Text( "Forgot Password", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.w300, - fontFamily: "Nunito", + color: Color(0xFF212121), // Text color decoration: TextDecoration.underline, // Underline the text @@ -686,10 +691,10 @@ class _LoginWidgetState extends State { }, child: Text( "Back to Login", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 11, fontWeight: FontWeight.w300, - fontFamily: "Nunito", + color: Color(0xFF212121), // Text color decoration: TextDecoration.underline, // Underline the text @@ -726,10 +731,8 @@ class _LoginWidgetState extends State { children: [ Text( "Sign In With Microsoft", - style: TextStyle( - fontFamily: "Nunito", - fontWeight: FontWeight.w500, - fontSize: 15), + style: GoogleFonts.poppins( + fontWeight: FontWeight.w500, fontSize: 14), ), SizedBox( width: 3, @@ -785,10 +788,9 @@ class _LoginWidgetState extends State { padding: const EdgeInsets.only(bottom: 8), child: Text( text, - style: const TextStyle( - fontSize: 11, - fontWeight: FontWeight.w700, - fontFamily: "Nunito", + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w600, color: Color(0xFF212121)), ), ), @@ -803,7 +805,7 @@ class _LoginWidgetState extends State { contentPadding: EdgeInsets.symmetric(vertical: 1.0, horizontal: 0.0), filled: true, fillColor: Colors.white, - labelStyle: TextStyle(fontSize: 11, color: Colors.grey), + labelStyle: GoogleFonts.poppins(fontSize: 11, color: Colors.grey), border: OutlineInputBorder( borderRadius: BorderRadius.circular(18), borderSide: BorderSide( diff --git a/lib/Screens/group/group.dart b/lib/Screens/group/group.dart index aca13cb..c0fa831 100644 --- a/lib/Screens/group/group.dart +++ b/lib/Screens/group/group.dart @@ -8,6 +8,7 @@ import 'package:frontend/Screens/organization/mailSettings.dart'; import 'package:frontend/Screens/organization/themeColor.dart'; import 'package:frontend/utils/auth_utils.dart'; import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; import 'package:responsive_builder/responsive_builder.dart'; @@ -415,7 +416,7 @@ class _groupState extends State { children: [ Text( "Create Group", - style: TextStyle(fontSize: 18), + style: GoogleFonts.poppins(fontSize: 18), ), // Container( // color: Color(0xFFE9EBF6), diff --git a/lib/Screens/organization/mailSettings.dart b/lib/Screens/organization/mailSettings.dart index 635dd62..f8af175 100644 --- a/lib/Screens/organization/mailSettings.dart +++ b/lib/Screens/organization/mailSettings.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import '../../config/apiUrl.dart'; @@ -224,7 +225,7 @@ class _MailSettingState extends State { children: [ Text( "Sender Email", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -254,11 +255,11 @@ class _MailSettingState extends State { "Invalid email format"; } }, - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "sender email", - labelStyle: - TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: GoogleFonts.poppins( + fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -315,7 +316,7 @@ class _MailSettingState extends State { children: [ Text( "Test Mail", - style: TextStyle( + style: GoogleFonts.poppins( color: Color(0xFF114D8B), fontWeight: FontWeight.w600), ), ], @@ -340,7 +341,7 @@ class _MailSettingState extends State { children: [ Text( "User Name", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -360,10 +361,11 @@ class _MailSettingState extends State { onChanged: (value) { _clearError("mail_user_name"); }, - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "user name", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: + GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -385,7 +387,7 @@ class _MailSettingState extends State { children: [ Text( "Password", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -409,7 +411,8 @@ class _MailSettingState extends State { style: TextStyle(fontSize: 12), decoration: InputDecoration( labelText: "password", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: + GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -449,7 +452,7 @@ class _MailSettingState extends State { children: [ Text( "Host", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -469,10 +472,11 @@ class _MailSettingState extends State { onChanged: (value) { _clearError("mail_host"); }, - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "host", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: + GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -494,7 +498,7 @@ class _MailSettingState extends State { children: [ Text( "Port", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -514,10 +518,11 @@ class _MailSettingState extends State { onChanged: (value) { _clearError("mail_port"); }, - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "port", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: + GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -544,7 +549,7 @@ class _MailSettingState extends State { children: [ Text( "Enter Your Mail Id", - style: TextStyle( + style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)), @@ -573,10 +578,11 @@ class _MailSettingState extends State { errorMessages["to_mail"] = "Invalid email format"; } }, - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), decoration: InputDecoration( labelText: "To mail", - labelStyle: TextStyle(fontSize: 12, color: Colors.grey), + labelStyle: + GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, contentPadding: EdgeInsets.symmetric(vertical: 16), @@ -616,7 +622,7 @@ class _MailSettingState extends State { }, child: Text( "Test Email", - style: TextStyle(fontSize: 12), + style: GoogleFonts.poppins(fontSize: 12), )) ], ), diff --git a/lib/Screens/organization/orgSetup.dart b/lib/Screens/organization/orgSetup.dart index 4cd4c74..7d189b5 100644 --- a/lib/Screens/organization/orgSetup.dart +++ b/lib/Screens/organization/orgSetup.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:frontend/Screens/organization/mailSettings.dart'; import 'package:frontend/Screens/organization/themeColor.dart'; import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; import 'package:http/http.dart' as http; import 'package:http_parser/http_parser.dart'; import 'package:image_picker/image_picker.dart'; @@ -444,7 +445,8 @@ class _OrgSetUpState extends State { child: Column( children: [ Container( - padding: const EdgeInsets.all(20), + padding: const EdgeInsets.only( + left: 20, right: 20, bottom: 20, top: 5), // height: MediaQuery.of(context).size.height * 0.8, color: Colors.white, child: Column( @@ -460,8 +462,8 @@ class _OrgSetUpState extends State { selectedOrg != null && selectedOrg!.isNotEmpty ? "Update Organization" : "Create Organization", - style: TextStyle( - fontSize: 15, fontWeight: FontWeight.w800), + style: GoogleFonts.poppins( + fontSize: 15, fontWeight: FontWeight.w500), ), ], ), @@ -472,12 +474,11 @@ class _OrgSetUpState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ - const Padding( - padding: EdgeInsets.only(top: 1.0), + Padding( + padding: const EdgeInsets.only(top: 1.0), child: Text( "Name:", - style: TextStyle( - fontFamily: "Archivo", + style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF212121)), @@ -487,14 +488,15 @@ class _OrgSetUpState extends State { Expanded( child: TextFormField( controller: _orgNameController, - style: TextStyle( + + style: GoogleFonts.poppins( fontSize: 16, color: Color(0xFF114D8B), ), decoration: InputDecoration( hintText: "Enter Organization Name", - hintStyle: - TextStyle(fontSize: 14, color: Colors.grey), + hintStyle: GoogleFonts.poppins( + fontSize: 14, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, border: InputBorder.none, @@ -543,8 +545,90 @@ class _OrgSetUpState extends State { ], ), ), + SizedBox( - height: 5, + height: 10, + ), + + Text( + "Services", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF212121)), + ), + SizedBox( + height: 10, + ), + Container( + decoration: BoxDecoration( + border: Border.all(color: Color(0xFFF4F4FB)), + borderRadius: BorderRadius.circular(1), + // color: bodyColor, + // color: Color(0xFFF5F5F5), + color: Colors.white), + padding: + EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5), + child: isDesktop + ? Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + // mainAxisSize: MainAxisSize.min, + children: _buildOptions(), + ) + : Expanded( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( + children: _buildOptions(), + ), + ), + ), + ), + SizedBox( + height: 15, + ), + + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Choose Theme", + style: GoogleFonts.poppins( + fontSize: 14, + fontWeight: FontWeight.w600, + color: Color(0xFF212121)), + ), + Container( + decoration: BoxDecoration( + // border: Border.all(color: Color(0xFFF4F4FB)), + borderRadius: BorderRadius.circular(1), + // color: Color(0xFFF4F4FB), + ), + padding: EdgeInsets.only( + left: 5, right: 5, top: 15, bottom: 5), + child: layoutColor != null && bodyColor != null + ? ColorThemePickerWidget( + initialLayoutColor: layoutColor, + initialBodyColor: bodyColor, + onLayoutColorSelected: + (Color selectedLayoutColor) { + setState(() { + layoutColor = selectedLayoutColor; + }); + }, + onBodyColorSelected: (Color selectedBodyColor) { + setState(() { + bodyColor = selectedBodyColor; + }); + }, + ) + : CircularProgressIndicator(), + ), + ], + ), + + SizedBox( + height: 15, ), Container( color: Colors.white, @@ -555,8 +639,7 @@ class _OrgSetUpState extends State { children: [ Text( "Mail Settings", - style: TextStyle( - fontFamily: "Archivo", + style: GoogleFonts.poppins( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFF212121)), @@ -615,89 +698,6 @@ class _OrgSetUpState extends State { )) ], )), - SizedBox( - height: 15, - ), - - Text( - "Services", - style: TextStyle( - fontFamily: "Archivo", - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF212121)), - ), - SizedBox( - height: 10, - ), - Container( - decoration: BoxDecoration( - border: Border.all(color: Color(0xFFF4F4FB)), - borderRadius: BorderRadius.circular(1), - // color: bodyColor, - // color: Color(0xFFF5F5F5), - color: Colors.white), - padding: - EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5), - child: isDesktop - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // mainAxisSize: MainAxisSize.min, - children: _buildOptions(), - ) - : Expanded( - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: Row( - children: _buildOptions(), - ), - ), - ), - ), - SizedBox( - height: 15, - ), - - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - "Choose Theme", - style: TextStyle( - fontFamily: "Archivo", - fontSize: 14, - fontWeight: FontWeight.w600, - color: Color(0xFF212121)), - ), - Container( - decoration: BoxDecoration( - // border: Border.all(color: Color(0xFFF4F4FB)), - borderRadius: BorderRadius.circular(1), - // color: Color(0xFFF4F4FB), - ), - padding: EdgeInsets.only( - left: 5, right: 5, top: 15, bottom: 5), - child: layoutColor != null && bodyColor != null - ? ColorThemePickerWidget( - initialLayoutColor: layoutColor, - initialBodyColor: bodyColor, - onLayoutColorSelected: - (Color selectedLayoutColor) { - setState(() { - layoutColor = selectedLayoutColor; - }); - }, - onBodyColorSelected: (Color selectedBodyColor) { - setState(() { - bodyColor = selectedBodyColor; - }); - }, - ) - : CircularProgressIndicator(), - ), - ], - ), - // isDesktop // ? Row( // mainAxisAlignment: MainAxisAlignment.end, @@ -775,21 +775,19 @@ class _OrgSetUpState extends State { color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569)), - SizedBox(width: 5), + SizedBox(width: 2), - SizedBox(width: 5), Text( name, - style: TextStyle( - fontSize: 13, + style: GoogleFonts.poppins( + fontSize: 12, color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569), - fontFamily: "Archivo", fontWeight: isSelected == name ? FontWeight.bold : FontWeight.w500), // fontWeight: selectedListOption == title ? FontWeight.bold : FontWeight.normal,)), ), - SizedBox(width: 5), + SizedBox(width: 2), // if (selectedListOption == title && widget.isViewMode == false) Container( height: 15, @@ -849,7 +847,10 @@ class _OrgSetUpState extends State { onPressed: () { context.go('/listPlan'); }, - child: Text("Cancel")), + child: Text( + "Cancel", + style: GoogleFonts.poppins(fontSize: 12), + )), SizedBox( width: 20, ), @@ -871,7 +872,10 @@ class _OrgSetUpState extends State { padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: handleSubmit, // Disable when in view mode - child: Text("Submit"), + child: Text( + "Submit", + style: GoogleFonts.poppins(fontSize: 12), + ), ), ) ]; diff --git a/lib/Screens/plans/list_plans.dart b/lib/Screens/plans/list_plans.dart index 23f34f8..aaf309f 100644 --- a/lib/Screens/plans/list_plans.dart +++ b/lib/Screens/plans/list_plans.dart @@ -379,7 +379,10 @@ class _ListPlansState extends State { ], ), - Spacer(), + // Spacer(), + SizedBox( + width: MediaQuery.of(context).size.width * 0.23, + ), if (isDesktop) Container( width: MediaQuery.of(context).size.width * 0.2, @@ -773,7 +776,8 @@ class _ListPlansState extends State { context); // Close popup manually ApiService.viewPlan( context, plan.planId, - isViewMode: true); + isViewMode: true, + isMyTrips: true); }, ), IconButton( @@ -785,7 +789,8 @@ class _ListPlansState extends State { Navigator.pop(context); ApiService.viewPlan( context, plan.planId, - isViewMode: false); + isViewMode: false, + isMyTrips: true); }, ), IconButton( diff --git a/lib/Screens/userManagement/create_user/create_user.dart b/lib/Screens/userManagement/create_user/create_user.dart index 6d54a6d..4a92562 100644 --- a/lib/Screens/userManagement/create_user/create_user.dart +++ b/lib/Screens/userManagement/create_user/create_user.dart @@ -70,6 +70,7 @@ class _CreateUserFormDetialsState extends State { late List? apiRoleData; late List? apiUserData; Map? apiselectedUser; + List> selectedServiceIds = []; late List userList; late Future> futureUsers; @@ -146,7 +147,7 @@ class _CreateUserFormDetialsState extends State { "address": controllers["address"]?.text, "gender": selectedGender, // "gender": personalDetailsKey.currentState?.selectedGender, - + "agent_supported_service_ids": selectedServiceIds, "postal_code": controllers["postalCode"]?.text, "country_code": selectedCountry, "employee_code": controllers["employeeCode"]?.text, @@ -270,6 +271,27 @@ class _CreateUserFormDetialsState extends State { selectedThirdApprover = apiselectedUser?["third_approver"]?.toString() ?? ""; } + try { + final raw = apiselectedUser!["agent_supported_service_ids"]; + + // Fix the invalid JSON (dangerous if the format changes) + final fixedJson = raw.replaceAllMapped( + RegExp(r'(\w+):'), // matches `service_id:` + (match) => '"${match.group(1)}":', + ); + + List decodedList = jsonDecode(fixedJson); + + selectedServiceIds = decodedList.map>((item) { + final map = Map.from(item); + return { + "service_id": map['service_id'].toString(), + }; + }).toList(); + } catch (e) { + print("❌ Error decoding fixed agent_supported_service_ids: $e"); + selectedServiceIds = []; + } print("Updated selectedGender: $selectedGender"); // Debugging @@ -932,6 +954,13 @@ class _CreateUserFormDetialsState extends State { selectedRole = role; }); }, + + onServiceIdsChanged: (List> updatedList) { + setState(() { + selectedServiceIds = updatedList; + }); + }, + initialSelectedServices: selectedServiceIds, ); case "office": return OfficeDetails( @@ -991,6 +1020,11 @@ class _CreateUserFormDetialsState extends State { selectedCountry: selectedCountry, apiselectedUser: isapiselectedUser, onUserTypeChanged: handleUserTypeChange, + onServiceIdsChanged: (List> updatedList) { + setState(() { + selectedServiceIds = updatedList; + }); + }, ); } } diff --git a/lib/Screens/userManagement/create_user/personal_details.dart b/lib/Screens/userManagement/create_user/personal_details.dart index eec4137..48671b5 100644 --- a/lib/Screens/userManagement/create_user/personal_details.dart +++ b/lib/Screens/userManagement/create_user/personal_details.dart @@ -20,10 +20,13 @@ class PersonalDetails extends StatefulWidget { final bool isViewMode; final bool apiselectedUser; + final Function(List>)? onServiceIdsChanged; + final ValueChanged? onGenderChanged; final ValueChanged? onCountryChanged; final ValueChanged? onRoleChanged; final void Function(bool)? onUserTypeChanged; + final List>? initialSelectedServices; final String? selectedGender; final String? selectedCountry; @@ -35,7 +38,9 @@ class PersonalDetails extends StatefulWidget { this.selectedGender, this.selectedCountry, this.selectedRole, + this.onServiceIdsChanged, required this.personalDetailsKey, + this.initialSelectedServices, required this.controllers, required this.errorMessages, required this.isDesktop, @@ -131,6 +136,10 @@ class PersonalDetailsState extends State { selectedRole = widget.selectedRole; fetchRoles(); fetchCountries(); + selectedServiceIds = + List>.from(widget.initialSelectedServices ?? []); + + print("selectedServiceIdsAPI - $selectedServiceIds"); WidgetsBinding.instance.addPostFrameCallback((_) { loadAllServices(); @@ -199,13 +208,22 @@ class PersonalDetailsState extends State { services = []; } - selectedServiceIds = services.map>((item) { - // force cast or copy to a regular map - final map = Map.from(item); - return { - "service_id": map['service_id'].toString(), - }; - }).toList(); + if (selectedServiceIds.isEmpty && services.isNotEmpty) { + selectedServiceIds = services.map>((item) { + final map = Map.from(item); + return { + "service_id": map['service_id'].toString(), + }; + }).toList(); + } + + // selectedServiceIds = services.map>((item) { + // // force cast or copy to a regular map + // final map = Map.from(item); + // return { + // "service_id": map['service_id'].toString(), + // }; + // }).toList(); }); // orgId = await getOrgId(); @@ -351,6 +369,9 @@ class PersonalDetailsState extends State { } else { selectedServiceIds.add({"service_id": serviceId}); } + + // Call the parent's callback + widget.onServiceIdsChanged!(selectedServiceIds); }); }, child: Row(children: [ @@ -755,7 +776,7 @@ class PersonalDetailsState extends State { setState(() { _selectedDateOfBirth = pickedDate; widget.controllers["dob"]?.text = - DateFormat('yyyy-MM-dd').format(pickedDate); + DateFormat('dd-MM-yyyy').format(pickedDate); }); } } diff --git a/lib/Screens/userManagement/create_user/traveller_details.dart b/lib/Screens/userManagement/create_user/traveller_details.dart index 400a152..21f497c 100644 --- a/lib/Screens/userManagement/create_user/traveller_details.dart +++ b/lib/Screens/userManagement/create_user/traveller_details.dart @@ -50,6 +50,7 @@ class TravellerDetailsState extends State { html.File? passportFile; late List isExpandedList; int? expandedIndex; + bool isCountryLoading = true; late final userId; String? selectedFileNames; @@ -79,6 +80,7 @@ class TravellerDetailsState extends State { Map countryMap = {}; late List? apiCountryData; + late List? apiAirlineCountryData; Map? apiData; final Map controllers = {}; @@ -86,7 +88,7 @@ class TravellerDetailsState extends State { "Passport Details", // "Local ID Details", "Visa Details", - "Frequent Flier Information", + "Frequent Flyer Information", "Hotel Loyalty Membership", "Preferences Domestic", "Preferences International", @@ -94,6 +96,7 @@ class TravellerDetailsState extends State { "Forex Details" ]; +//To Create Controllers List dataHeader = [ "Fname", "Lname", @@ -111,6 +114,7 @@ class TravellerDetailsState extends State { "forex_card_num", "full_name_as_id", "local_id_num", + "forex_expiry_date" ]; @override @@ -120,11 +124,13 @@ class TravellerDetailsState extends State { // userId = getUserId(); apiCountryData = null; + apiAirlineCountryData = []; apiData = null; for (var field in dataHeader) { controllers[field] = TextEditingController(); } fetchCountries(); + loadCountryList(); fetchApiData(); // Delay adding the row until after the first frame WidgetsBinding.instance.addPostFrameCallback((_) { @@ -170,7 +176,8 @@ class TravellerDetailsState extends State { frequentFlierEntries.add({ "local_id": localId, "id": null, // to be set when backend responds - "controller_airline": TextEditingController(), + // "controller_airline": null, + "airline": null, "controller_flier_number": TextEditingController(), "is_active": "1" }); @@ -196,7 +203,6 @@ class TravellerDetailsState extends State { "visa_type_id": null, "controller_valid_from": TextEditingController(), "controller_valid_upto": TextEditingController(), - "is_active": "1" }); setState(() {}); @@ -240,12 +246,13 @@ class TravellerDetailsState extends State { "date_of_expiry": controllers["dateOfExpiry"]?.text, "d_meal_preference": controllers["d_meal_pref"]?.text, "d_seat_preference": selectedDomesticSeat, - // "d_additonalInfo": controllers["d_additonal_Info"]?.text, + "d_additonalInfo": controllers["d_additonal_Info"]?.text, "i_meal_preference": controllers["i_meal_pref"]?.text, "i_seat_preference": selectedIntenationalSeat, - // "i_additonalInfo": controllers["i_additonal_Info"]?.text, + "i_additonalInfo": controllers["i_additonal_Info"]?.text, "emergency_contact_number": controllers["emergency_contact"]?.text, "forex_pre_paid_card_number": controllers["forex_card_num"]?.text, + "forex_expiry_date": controllers["forex_expiry_date"]?.text, // "frequent_flier_information": [], "frequent_flier_information": frequentFlierList, "hotel_membership": hotelMembershipList, @@ -270,14 +277,33 @@ class TravellerDetailsState extends State { }).toList(); } + // List> get frequentFlierList { + // return frequentFlierEntries + // // .where((entry) => entry["is_active"] != "0") // ✅ Only active entries + // .map((entry) { + // return { + // "id": entry["id"], + // "airline": entry["airline"], + // "frequent_flier_number": entry["controller_flier_number"].text, + // "created_by": null, + // "updated_by": null, + // "is_active": entry["is_active"] ?? "1", + // }; + // }).toList(); + // } + List> get frequentFlierList { - return frequentFlierEntries - // .where((entry) => entry["is_active"] != "0") // ✅ Only active entries - .map((entry) { + return frequentFlierEntries.map((entry) { + final frequent_flier_number = entry["controller_flier_number"]; + + print("frequent_flier_number- $frequent_flier_number"); + return { "id": entry["id"], - "airline": entry["controller_airline"].text, - "frequent_flier_number": entry["controller_flier_number"].text, + "airline": entry["airline"], // ✅ string value + "frequent_flier_number": frequent_flier_number is TextEditingController + ? frequent_flier_number.text + : "", "created_by": null, "updated_by": null, "is_active": entry["is_active"] ?? "1", @@ -346,10 +372,14 @@ class TravellerDetailsState extends State { controllers["d_meal_pref"]?.text = widget.travelDetails?["d_meal_preference"] ?? ""; - controllers["i_meal_pref"]?.text = widget.travelDetails?["i_meal_preference"] ?? ""; + controllers["d_additonal_Info"]?.text = + widget.travelDetails?["d_additonalInfo"] ?? ""; + controllers["i_additonal_Info"]?.text = + widget.travelDetails?["i_additonalInfo"] ?? ""; + selectedIntenationalSeat = widget.travelDetails?["i_seat_preference"] ?? ""; selectedDomesticSeat = widget.travelDetails?["d_seat_preference"] ?? ""; @@ -359,6 +389,8 @@ class TravellerDetailsState extends State { controllers["forex_card_num"]?.text = widget.travelDetails?["forex_pre_paid_card_number"] ?? ""; + controllers["forex_expiry_date"]?.text = + widget.travelDetails?["forex_expiry_date"] ?? ""; String? apiDocPath = widget.travelDetails?["passport_document"]; if (apiDocPath != null && apiDocPath.isNotEmpty) { @@ -402,38 +434,6 @@ class TravellerDetailsState extends State { } //---------------------------------------------------- - - // 🚨 Frequent Flier Logic (pre-fill for edit) - for (var entry in frequentFlierEntries) { - entry["controller_airline"].dispose(); - entry["controller_flier_number"].dispose(); - } - frequentFlierEntries.clear(); - - final frequentFlierList = - widget.travelDetails?['frequent_flier_information']; - if (frequentFlierList != null && frequentFlierList is List) { - for (var item in frequentFlierList) { - if (item["is_active"]?.toString() == "0") continue; - - final localId = _rowFlierCounter++; - frequentFlierEntries.add({ - "local_id": localId, - "id": item["id"], - "controller_airline": - TextEditingController(text: item["airline"] ?? ""), - "controller_flier_number": TextEditingController( - text: item["frequent_flier_number"] ?? ""), - }); - } - - if (frequentFlierEntries.isEmpty) { - addFrequentFlierEntry(); - } - } - - //---------------------------------------------------- - // 🚨 Visa Logic (pre-fill for edit) for (var entry in visaEntries) { entry["controller_valid_from"]?.dispose(); @@ -463,6 +463,40 @@ class TravellerDetailsState extends State { addVisaEntry(); } } + // ---------------------------------------------------- + + // 🚨 Frequent Flier Logic (pre-fill for edit) + for (var entry in frequentFlierEntries) { + // entry["controller_airline"].dispose(); + entry["controller_flier_number"].dispose(); + } + frequentFlierEntries.clear(); + + final frequentFlierList = + widget.travelDetails?['frequent_flier_information']; + + if (frequentFlierList != null && frequentFlierList is List) { + for (var item in frequentFlierList) { + if (item["is_active"]?.toString() == "0") continue; + + final localId = _rowFlierCounter++; + final airlineCode = item["airline"]; + + frequentFlierEntries.add({ + "local_id": localId, + "id": item["id"], + "airline": airlineCode ?? "", + "controller_flier_number": TextEditingController( + text: item["frequent_flier_number"] ?? ""), + }); + } + + if (frequentFlierEntries.isEmpty) { + addFrequentFlierEntry(); + } + } + + //---------------------------------------------------- setState(() {}); } @@ -479,6 +513,35 @@ class TravellerDetailsState extends State { } } + Future loadCountryList() async { + final newTripType = "2"; + final result = await apiService.fetchFlightsCountryList(newTripType); + + print("resultFlight: $result "); + + setState(() { + apiAirlineCountryData = result; + }); + + // print("ResultCountry : $result"); + // + // // Create a map: Country_Code -> "City, Airport" + // Map tempCountryMap = {}; + // + // for (var country in result) { + // String city = country['City'] ?? ''; + // String airport = country['Airport'] ?? ''; + // String displayName = '${country['City']} - ${country['Airport']}'; + // + // tempCountryMap[country['Code']] = displayName; + // } + // + // setState(() { + // countryMap = tempCountryMap; // Update the map + // isCountryLoading = false; + // }); + } + Future fetchApiData() async { try { final data = await apiService.fetchMasterDropdown(); @@ -605,7 +668,7 @@ class TravellerDetailsState extends State { case "Visa Details": return _buildVisaDetails(widget.isDesktop); - case "Frequent Flier Information": + case "Frequent Flyer Information": return _buildFrequentFlierInfo(widget.isDesktop); case "Hotel Loyalty Membership": @@ -960,7 +1023,7 @@ class TravellerDetailsState extends State { setState(() { _selectedDateOfIssue = pickedDate; controllers["dateOfIssue"]?.text = - DateFormat('yyyy-MM-dd').format(pickedDate); + DateFormat('dd-MM-yyyy').format(pickedDate); }); } } @@ -1038,7 +1101,7 @@ class TravellerDetailsState extends State { setState(() { _selectedDateOfExpiry = pickedDate; controllers["dateOfExpiry"]?.text = - DateFormat('yyyy-MM-dd').format(pickedDate); + DateFormat('dd-MM-yyyy').format(pickedDate); // controllers["dateOfExpiry"]?.text = // DateFormat('dd-MM-yyyy').format(pickedDate); @@ -1497,8 +1560,8 @@ class TravellerDetailsState extends State { buildDomesticSeatType(), SizedBox(width: 15), buildDomesticMealPref(), - // SizedBox(width: 15), - // buildDomesticAddtnlPref(), + SizedBox(width: 15), + buildDomesticAddtnlPref(), ], ) : Column( @@ -1507,9 +1570,9 @@ class TravellerDetailsState extends State { buildDomesticSeatType(), SizedBox(height: 8), buildDomesticMealPref(), - // SizedBox(height: 8), // Vertical space - // - // buildDomesticAddtnlPref(), + SizedBox(height: 8), // Vertical space + + buildDomesticAddtnlPref(), ], ), ); @@ -1702,8 +1765,8 @@ class TravellerDetailsState extends State { buildInternationalSeatType(), SizedBox(width: 15), buildInternationalMealPref(), - // SizedBox(width: 15), - // buildInternationalAddtnlPref(), + SizedBox(width: 15), + buildInternationalAddtnlPref(), ], ) : Column( @@ -1712,9 +1775,9 @@ class TravellerDetailsState extends State { buildInternationalSeatType(), SizedBox(height: 8), buildInternationalMealPref(), - // SizedBox(height: 8), // Vertical space - // - // buildInternationalAddtnlPref(), + SizedBox(height: 8), // Vertical space + + buildInternationalAddtnlPref(), ], ), ); @@ -1947,11 +2010,34 @@ class TravellerDetailsState extends State { SizedBox( height: 10, ), - buildForexCardNumber(), + _buildForexDetailDataRow1(isDesktop), ], ); } + Widget _buildForexDetailDataRow1(bool isDesktop) { + return Container( + color: Colors.white, + child: widget.isDesktop + ? Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildForexCardNumber(), + SizedBox(width: 15), + buildForexExpiryDate(), + ], + ) + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildForexCardNumber(), + SizedBox(height: 8), + buildForexExpiryDate() + ], + ), + ); + } + Widget buildForexCardNumber() { return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -1989,6 +2075,79 @@ class TravellerDetailsState extends State { ); } + Widget buildForexExpiryDate() { + DateTime? _selectedExpiryDate; + + Future _selectExpiryDate(BuildContext context) async { + DateTime now = DateTime.now(); + DateTime today = DateTime(now.year, now.month, now.day); + + DateTime? pickedDate = await showDatePicker( + context: context, + initialDate: + _selectedExpiryDate != null && _selectedExpiryDate!.isAfter(today) + ? _selectedExpiryDate! + : today, + firstDate: DateTime(1900), + lastDate: DateTime(2100), + ); + + if (pickedDate != null && pickedDate != _selectedExpiryDate) { + setState(() { + _selectedExpiryDate = pickedDate; + // controllers["forex_expiry_date"]?.text = + // DateFormat('yyyy-MM-dd').format(pickedDate); + controllers["forex_expiry_date"]?.text = + DateFormat('dd-MM-yyyy').format(pickedDate); + }); + } + } + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "Forex Expiry Date", + style: GoogleFonts.poppins( + fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black), + ), + SizedBox(height: 5), + CustomTextFieldUserTravellerWrapper( + isFocused: false, + isDesktop: widget.isDesktop, + child: SizedBox( + height: 40, + child: GestureDetector( + onTap: widget.isViewMode + ? null + : () async { + await _selectExpiryDate(context); + }, + child: AbsorbPointer( + child: TextField( + controller: controllers["forex_expiry_date"], + style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), + decoration: InputDecoration( + labelText: "Select Date", + labelStyle: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w400, + color: Colors.grey), + floatingLabelBehavior: FloatingLabelBehavior.never, + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric(vertical: 16), + suffixIcon: Icon(Icons.calendar_today, + size: 16, color: Color(0xFF8B8FB2)), + ), + ), + ), + ), + ), + ), + ], + ); + } + //-------------------------Frequent Flier Information ------------------------------- Widget _buildFrequentFlierInfo(bool isDesktop) { @@ -2056,6 +2215,50 @@ class TravellerDetailsState extends State { } Widget buildAirline(Map entry) { + late Map countryMap; // Mapping country_code -> country_name + late List countryCodes; // List of country codes + + // countryList = []; + bool hasAirlineCountryData = + apiAirlineCountryData == null || apiAirlineCountryData!.isEmpty; + + countryList = apiAirlineCountryData!; + print("TestcountryList2 - $countryList"); + + countryMap = { + for (var country in countryList) + country['Code'] as String: '${country['City']} - ${country['Airport']}' + }; + + countryCodes = countryMap.keys.toList(); + + // setState(() { + // countryMap = tempCountryMap; // Update the map + // isCountryLoading = false; + // }); + + // Map country codes to country names + // countryMap = { + // + // + // for (var item in countryList) + // item['country_code'] as String: item['country_name'] as String + // }; + + // Extract only country codes for processing + +//-------------------------- + + // String? selectedCountry = entry['airline']; + String? selectedCode = entry['airline']; + String? selectedText = + selectedCode != null ? countryMap[selectedCode] : null; + + print("selectedCode: $selectedCode"); + print("selectedText: $selectedText"); + print( + "items.contains(selectedText): ${countryMap.values.contains(selectedText)}"); + return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -2067,30 +2270,105 @@ class TravellerDetailsState extends State { SizedBox(height: 5), CustomTextFieldUserTravellerWrapper( width: widget.isDesktop - ? MediaQuery.of(context).size.width * 0.15 + ? MediaQuery.of(context).size.width * 0.17 : null, isFocused: false, isDesktop: widget.isDesktop, child: SizedBox( height: 40, - child: TextField( - style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), - controller: entry["controller_airline"], - enabled: !widget.isViewMode, - onChanged: (value) { - _clearError("first_name"); - }, - decoration: InputDecoration( - labelText: "Airline", - labelStyle: - GoogleFonts.poppins(fontSize: 12, color: Colors.grey), - floatingLabelBehavior: FloatingLabelBehavior.never, - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 16), - ), - ), + child: hasAirlineCountryData + ? CircularProgressIndicator() + : DropdownSearch( + // selectedItem: countryMap[selectedCountry], + // selectedItem: entry['airline'] != null + // ? countryMap[entry['airline']] + // : null, + // selectedItem: countryMap.containsKey(entry['airline']) + // ? countryMap[entry['airline']] + // : null, + // selectedItem: countryMap[selectedCode], + // selectedItem: countryMap.containsKey(selectedCode) + // ? countryMap[selectedCode] + // : null, + selectedItem: (entry["airline"] != null && + countryMap.containsKey(entry["airline"])) + ? countryMap[entry["airline"]] + : null, + + popupProps: PopupProps.menu( + showSearchBox: true, // Enables search functionality + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Country...", + contentPadding: EdgeInsets.symmetric(horizontal: 10), + ), + ), + ), + items: countryMap.values.toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + border: InputBorder.none, + contentPadding: EdgeInsets.symmetric( + horizontal: 1, + ), + ), + ), + dropdownBuilder: (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select Country", + style: TextStyle(fontSize: 12), + ), + ), + onChanged: (String? newValue) { + setState(() { + // Find the country_code based on selected country_name + // selectedCountry = countryMap.entries + // .firstWhere((entry) => entry.value == newValue) + // .key; + + final selectedCode = countryMap.entries + .firstWhere((entry) => entry.value == newValue) + .key; + entry['airline'] = selectedCode; + + // final selectedCode = countryMap.entries + // .firstWhere((entry) => entry.value == newValue) + // .key; + // entry['airline'] = selectedCode; + }); + }, + ), ), ), + + // CustomTextFieldUserTravellerWrapper( + // width: widget.isDesktop + // ? MediaQuery.of(context).size.width * 0.15 + // : null, + // isFocused: false, + // isDesktop: widget.isDesktop, + // child: SizedBox( + // height: 40, + // child: TextField( + // style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), + // controller: entry["controller_airline"], + // enabled: !widget.isViewMode, + // onChanged: (value) { + // _clearError("first_name"); + // }, + // decoration: InputDecoration( + // labelText: "Airline", + // labelStyle: + // GoogleFonts.poppins(fontSize: 12, color: Colors.grey), + // floatingLabelBehavior: FloatingLabelBehavior.never, + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(vertical: 16), + // ), + // ), + // ), + // ), ], ); } @@ -2102,7 +2380,7 @@ class TravellerDetailsState extends State { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - "Frequent Flier Information", + "Frequent Flyer Information", style: GoogleFonts.poppins( fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black), ), @@ -2120,7 +2398,7 @@ class TravellerDetailsState extends State { _clearError("first_name"); }, decoration: InputDecoration( - labelText: "Frequent Flier Information", + labelText: "Frequent Flyer Information", labelStyle: GoogleFonts.poppins(fontSize: 12, color: Colors.grey), floatingLabelBehavior: FloatingLabelBehavior.never, @@ -2145,7 +2423,7 @@ class TravellerDetailsState extends State { size: 30, ), onPressed: () => addFrequentFlierEntry(), - tooltip: "Frequent Flier Information", + tooltip: "Frequent Flyer Information", ), ); } @@ -2397,6 +2675,8 @@ class TravellerDetailsState extends State { // countryList = []; countryList = apiCountryData ?? []; + print("TestcountryList1 - $countryList"); + // Map country codes to country names countryMap = { for (var item in countryList) @@ -2593,7 +2873,7 @@ class TravellerDetailsState extends State { // _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate); entry["controller_valid_from"].text = - DateFormat('yyyy-MM-dd').format(pickedDate); + DateFormat('dd-MM-yyyy').format(pickedDate); }); } } @@ -2673,7 +2953,7 @@ class TravellerDetailsState extends State { // _dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate); entry["controller_valid_upto"].text = - DateFormat('yyyy-MM-dd').format(pickedDate); + DateFormat('dd-MM-yyyy').format(pickedDate); }); } } diff --git a/lib/routes/custom_appBar.dart b/lib/routes/custom_appBar.dart index 093004e..0cc3fc1 100644 --- a/lib/routes/custom_appBar.dart +++ b/lib/routes/custom_appBar.dart @@ -6,7 +6,7 @@ import 'package:shared_preferences/shared_preferences.dart'; // don't forget import '../services/apiService.dart'; import '../utils/auth_utils.dart'; -enum TabSelection { allTrips, myTrips, myApprovals } +enum TabSelection { allTrips, myTrips, myApprovals, allMenu } class CustomAppBar extends StatefulWidget implements PreferredSizeWidget { final bool isDesktop; @@ -34,7 +34,7 @@ class CustomAppBar extends StatefulWidget implements PreferredSizeWidget { class _CustomAppBarState extends State { final ApiService apiService = ApiService(); - TabSelection selectedTab = TabSelection.allTrips; + late TabSelection selectedTab; String? token; Map? userData; @@ -43,14 +43,10 @@ class _CustomAppBarState extends State { Map profileUserDetails = {}; Map? selectedOrg; - Color? layoutColor; + // Color? layoutColor; + Color? layoutColor = Colors.white10; Color? bodyColor; - Color _myTravelRequestColor = Color(0xFF475569); // Default color - EdgeInsets _myTravelRequestPadding = - EdgeInsets.symmetric(horizontal: 8, vertical: 4); - Color _myApprovalsColor = Color(0xFF475569); // Default color - void initState() { super.initState(); // initializeData(); @@ -58,6 +54,12 @@ class _CustomAppBarState extends State { initializeData(); getOrganizationData(); }); + if (userData?["role"] == "Org Admin" || + userData?["role"] == "Travel Admin") { + selectedTab = TabSelection.allTrips; + } else { + selectedTab = TabSelection.myTrips; + } } Future getProfileUser() async { @@ -94,17 +96,6 @@ class _CustomAppBarState extends State { getProfileUser(); } - String getTabLabel(TabSelection tab) { - switch (tab) { - case TabSelection.allTrips: - return "All Trips"; - case TabSelection.myTrips: - return "My Trips"; - case TabSelection.myApprovals: - return "My Approvals"; - } - } - Future getToken() async { final prefs = await SharedPreferences.getInstance(); return prefs.getString("auth_token"); @@ -174,6 +165,43 @@ class _CustomAppBarState extends State { } } + void handleTabChange(TabSelection tab, String route) { + final currentUri = + GoRouterState.of(context).uri.toString(); // ✅ safer than `.location` + print("currentUri - $currentUri"); + + if (currentUri != route) { + setState(() { + selectedTab = tab; + }); + context.go(route); + } + } + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + final location = GoRouterState.of(context).uri.toString(); + + print("location - $location"); + + setState(() { + if (location.contains('/listAllPlan') || + location.contains('/allTrips/trips')) { + selectedTab = TabSelection.allTrips; + } else if (location.contains('/listPlan') || + location.contains('/createPlan') || + location.contains('/listTravelAgentPlan')) { + selectedTab = TabSelection.myTrips; + } else if (location.contains('/ApprovalList')) { + selectedTab = TabSelection.myApprovals; + } else { + selectedTab = TabSelection.allMenu; + } + }); + } + @override Widget build(BuildContext context) { return AppBar( @@ -216,7 +244,7 @@ class _CustomAppBarState extends State { ) : const CircleAvatar( radius: 20, - backgroundColor: Colors.white, + // backgroundColor: Colors.white, child: Icon( Icons.add_a_photo, size: 10, @@ -225,186 +253,8 @@ class _CustomAppBarState extends State { ), ), SizedBox( - width: MediaQuery.of(context).size.width * 0.2, + width: MediaQuery.of(context).size.width * 0.18, ), - // Container( - // width: MediaQuery.of(context).size.width * 0.35, - // // color: Colors.blueGrey, - // child: Row( - // // crossAxisAlignment: CrossAxisAlignment.start, - // mainAxisAlignment: MainAxisAlignment.center, - // children: [ - // if (userData?["role"] == "Org Admin" || - // userData?["role"] == "Travel Admin") - // MouseRegion( - // cursor: SystemMouseCursors.click, - // onEnter: (_) { - // setState(() { - // // _myTravelRequestPadding = - // // EdgeInsets.symmetric(horizontal: 12, vertical: 78); - // // _myTravelRequestColor = - // // Color(0xFF114D8B); // Change color on hover - // }); - // }, - // onExit: (_) { - // setState(() { - // // _myTravelRequestPadding = EdgeInsets.symmetric( - // // horizontal: 8, vertical: 4); // Normal padding - // // _myTravelRequestColor = - // // Color(0xFF475569); // Revert color when hover ends - // }); - // }, - // child: InkWell( - // onTap: () { - // context.go('/listAllPlan'); - // }, - // child: Text( - // "All Trips", - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // // color: Color(0xFF475569), - // color: _myTravelRequestColor, - // fontFamily: "Inter", - // ), - // )), - // ), - // const SizedBox(width: 20), - // if (userDetails["role"] == "Travel Agent") - // MouseRegion( - // cursor: SystemMouseCursors.click, - // onEnter: (_) { - // setState(() { - // // _myTravelRequestPadding = - // // EdgeInsets.symmetric(horizontal: 12, vertical: 78); - // // _myTravelRequestColor = - // // Color(0xFF114D8B); // Change color on hover - // }); - // }, - // onExit: (_) { - // setState(() { - // // _myTravelRequestPadding = EdgeInsets.symmetric( - // // horizontal: 8, vertical: 4); // Normal padding - // // _myTravelRequestColor = - // // Color(0xFF475569); // Revert color when hover ends - // }); - // }, - // child: InkWell( - // onTap: () { - // context.go('/listTravelAgentPlan'); - // }, - // child: Text( - // "My Trips", - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // // color: Color(0xFF475569), - // color: _myTravelRequestColor, - // fontFamily: "Inter", - // ), - // )), - // ), - // if (userDetails["role"] != "Travel Agent") - // const SizedBox(width: 20), - // if (userDetails["role"] != "Travel Agent") - // MouseRegion( - // cursor: SystemMouseCursors.click, - // onEnter: (_) { - // setState(() { - // // _myTravelRequestPadding = - // // EdgeInsets.symmetric(horizontal: 12, vertical: 78); - // // _myTravelRequestColor = - // // Color(0xFF114D8B); // Change color on hover - // }); - // }, - // onExit: (_) { - // setState(() { - // // _myTravelRequestPadding = EdgeInsets.symmetric( - // // horizontal: 8, vertical: 4); // Normal padding - // // _myTravelRequestColor = - // // Color(0xFF475569); // Revert color when hover ends - // }); - // }, - // child: InkWell( - // onTap: () { - // context.go('/listPlan'); - // }, - // child: Text( - // "My Trips", - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // // color: Color(0xFF475569), - // color: _myTravelRequestColor, - // fontFamily: "Inter", - // ), - // )), - // ), - // const SizedBox(width: 20), - // if (userData?["role"] != "Travel Agent") - // MouseRegion( - // cursor: SystemMouseCursors.click, - // onEnter: (_) { - // setState(() { - // _myApprovalsColor = - // Color(0xFF114D8B); // Change color on hover - // }); - // }, - // onExit: (_) { - // setState(() { - // _myApprovalsColor = Color( - // 0xFF475569); // Revert color when hover ends - // }); - // }, - // child: InkWell( - // onTap: () { - // context.go('/ApprovalList'); - // }, - // child: Text( - // "My Approvals", - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // color: _myApprovalsColor, - // // color: Color(0xFF475569), - // fontFamily: "Inter", - // ), - // )), - // ), - // if (userData?["role"] == "Travel Agent") - // MouseRegion( - // cursor: SystemMouseCursors.click, - // onEnter: (_) { - // setState(() { - // _myApprovalsColor = - // Color(0xFF114D8B); // Change color on hover - // }); - // }, - // onExit: (_) { - // setState(() { - // _myApprovalsColor = Color( - // 0xFF475569); // Revert color when hover ends - // }); - // }, - // child: InkWell( - // onTap: () { - // context.go('/listTravelAgentPlan'); - // }, - // child: Text( - // "My Approvals", - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // color: _myApprovalsColor, - // // color: Color(0xFF475569), - // fontFamily: "Inter", - // ), - // )), - // ), - // ], - // ), - // ), - Container( width: MediaQuery.of(context).size.width * 0.35, child: Row( @@ -412,9 +262,14 @@ class _CustomAppBarState extends State { children: [ if (userData?["role"] == "Org Admin" || userData?["role"] == "Travel Admin") - buildNavItem("All Trips", _myTravelRequestColor, - () => context.go('/listAllPlan'), - isSelected: selectedTab == "All Trips"), + buildNavItem( + "All Trips", + () => handleTabChange( + TabSelection.allTrips, '/listAllPlan'), + layoutColor!, + isSelected: selectedTab == TabSelection.allTrips, + icon: Icons.insights_outlined, + ), if (userDetails["role"] != "Travel Agent") const SizedBox(width: 20), @@ -422,17 +277,23 @@ class _CustomAppBarState extends State { if (userData?["role"] == "Travel Agent") buildNavItem( "My Trips", - _myTravelRequestColor, - () => context.go('/listTravelAgentPlan'), - isSelected: selectedTab == "My Trips", + () => handleTabChange( + TabSelection.myTrips, '/listTravelAgentPlan'), + layoutColor!, + // () => context.go('/listTravelAgentPlan'), + isSelected: selectedTab == TabSelection.myTrips, + icon: Icons.request_page_outlined, ), if (userData?["role"] != "Travel Agent") // for others buildNavItem( "My Trips", - _myTravelRequestColor, - () => context.go('/listPlan'), - isSelected: selectedTab == "My Trips", + () => handleTabChange( + TabSelection.myTrips, '/listPlan'), + layoutColor!, + // () => context.go('/listPlan'), + isSelected: selectedTab == TabSelection.myTrips, + icon: Icons.request_page_outlined, ), // if (userDetails["role"] == "Travel Agent") // buildNavItem("My Trips", _myTravelRequestColor, @@ -448,11 +309,23 @@ class _CustomAppBarState extends State { const SizedBox(width: 20), if (userData?["role"] != "Travel Agent") - buildNavItem("My Approvals", _myApprovalsColor, () { - isSelected: - selectedTab == "My Approvals"; - context.go('/ApprovalList'); - }) + buildNavItem( + "My Approvals", + + () => handleTabChange( + TabSelection.myApprovals, '/ApprovalList'), + layoutColor!, + // () => context.go('/ApprovalList'), + isSelected: selectedTab == TabSelection.myApprovals, + icon: Icons.assessment_outlined, + ), + + // buildNavItem("My Approvals", _myApprovalsColor, () { + // isSelected: + // selectedTab == "My Approvals", + // context.go('/ApprovalList'), + // icon:Icons.insights_outlined; + // }) // if (userData?["role"] == "Travel Agent") { // isSelected: @@ -466,7 +339,6 @@ class _CustomAppBarState extends State { ], ), ), - Spacer(), ], ), @@ -664,11 +536,64 @@ PopupMenuItem buildMenuItem(Map item) { ); } -Widget buildNavItem(String label, Color color, VoidCallback onTap, - {bool isSelected = false}) { +Widget buildNavItem(String label, VoidCallback onTap, Color? layoutColor, + {bool isSelected = true, IconData? icon}) { + final effectiveColor = + isSelected ? (layoutColor ?? Colors.blue) : Colors.black; + return MouseRegion( cursor: SystemMouseCursors.click, - child: InkWell( + child: GestureDetector( + onTap: onTap, + child: Stack( + clipBehavior: Clip.none, + children: [ + Row( + children: [ + if (icon != null) Icon(icon, size: 16, color: effectiveColor), + if (icon != null) const SizedBox(width: 4), + Text( + label, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w500, + color: effectiveColor, + ), + ), + ], + ), + if (isSelected) + AnimatedPositioned( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + bottom: -20, + left: 0, + right: 0, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: 1.0, + child: AnimatedContainer( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + height: 2, + width: isSelected + ? 50 + : 0, // Animate width (make sure isSelected changes) + color: effectiveColor, + ), + ), + ), + ], + ), + ), + ); +} + +Widget buildNavItem1(String label, VoidCallback onTap, + {bool isSelected = true, IconData? icon}) { + return MouseRegion( + cursor: SystemMouseCursors.click, + child: GestureDetector( onTap: onTap, child: Container( padding: EdgeInsets.only(bottom: 2), @@ -676,22 +601,43 @@ Widget buildNavItem(String label, Color color, VoidCallback onTap, ? BoxDecoration( border: Border( bottom: BorderSide( - color: color, // underline color - width: 2, // underline thickness - ), + width: 2, // underline thickness + color: Colors.red), ), ) : null, // no underline when not selected - child: Text( - label, - style: GoogleFonts.poppins( - fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black), - // style: TextStyle( - // fontSize: 12, - // fontWeight: FontWeight.w600, - // color: color, - // fontFamily: "Inter", - // ), + child: Row( + children: [ + if (icon != null) + Icon( + icon, + size: 16, + color: isSelected ? Colors.red : Colors.black, + // color: Colors.red, + ), + if (icon != null) SizedBox(width: 4), + Text( + label, + style: GoogleFonts.poppins( + fontSize: 12, + fontWeight: FontWeight.w500, + color: isSelected ? Colors.red : Colors.black, + // color: Colors.red, + ), + ), + + // Red underline positioned below (e.g. under green line) + if (isSelected) + Positioned( + bottom: -50, // adjust this to push it below green line + left: 0, + right: 0, + child: Container( + height: 2, + color: Colors.red, + ), + ), + ], ), ), ), diff --git a/lib/routes/custom_drawer.dart b/lib/routes/custom_drawer.dart index 9fb6fbe..94bccea 100644 --- a/lib/routes/custom_drawer.dart +++ b/lib/routes/custom_drawer.dart @@ -173,11 +173,11 @@ class _CustomDrawerState extends State { if (userData?["role"] == "Org Admin" || userData?["role"] == "Travel Admin") - _buildDrawerItem(context, Icons.request_page_outlined, - 'All Trips', '/listAllPlan'), + _buildDrawerItem(context, Icons.insights_outlined, 'All Trips', + '/listAllPlan'), if (userDetails["role"] == "Travel Agent") - _buildDrawerItem(context, Icons.request_page_outlined, + _buildDrawerItem(context, Icons.assessment_outlined, 'My Approvals', '/listTravelAgentPlan'), if (userDetails["role"] != "Travel Agent") diff --git a/lib/routes/custom_router.dart b/lib/routes/custom_router.dart index 3ec834d..7cd0641 100644 --- a/lib/routes/custom_router.dart +++ b/lib/routes/custom_router.dart @@ -47,6 +47,10 @@ final GoRouter router = GoRouter( path: '/createPlan', builder: (context, state) => CreatePlan(), ), + GoRoute( + path: '/allTrips/trips', + builder: (context, state) => CreatePlan(), + ), GoRoute( path: '/listUser', builder: (context, state) => UserListScreen(), diff --git a/lib/services/apiService.dart b/lib/services/apiService.dart index 7a70f31..cc64df5 100644 --- a/lib/services/apiService.dart +++ b/lib/services/apiService.dart @@ -412,12 +412,12 @@ class ApiService { } static Future viewPlan(BuildContext context, String planId, - {bool isViewMode = false}) async { + {bool isViewMode = false, bool isMyTrips = false}) async { try { Map planData = await getViewPlan(planId); print("ViewAAA - $planData"); - context.go('/createPlan', + context.go(isMyTrips ? '/createPlan' : '/allTrips/trips', extra: {'planData': planData, 'isViewMode': isViewMode}); } catch (e) { print("Error fetching plan: $e");