diff --git a/lib/Screens/allTrips/list_all_plans.dart b/lib/Screens/allTrips/list_all_plans.dart index 9e0598e..f9e427e 100644 --- a/lib/Screens/allTrips/list_all_plans.dart +++ b/lib/Screens/allTrips/list_all_plans.dart @@ -503,7 +503,10 @@ class _ListAllPlansState extends State { return Container( margin: isDesktop ? EdgeInsets.all(10.0) : null, - padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20), + padding: + isDesktop + ? const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20) + : EdgeInsets.all(3.0), height: isDesktop ? MediaQuery.of(context).size.height * 0.98 @@ -1177,302 +1180,622 @@ class _ListAllPlansState extends State { // shadowColor: Colors.black54, // Softer shadow // clipBehavior: Clip.antiAlias, child: Padding( - padding: const EdgeInsets.all(12.0), - // padding: EdgeInsets.symmetric(vertical: 12), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + padding: const EdgeInsets.all(10.0), + + child: Row( children: [ - // Status and Employee Code - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, + Container( + // color: Colors.red.shade50, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: + CrossAxisAlignment.center, + children: [ + Image.asset( + plan.tripType == 'Domestic' + ? 'assets/images/IconsImg/Domestic_new.png' + : 'assets/images/IconsImg/International_new.png', + // width: 65, + height: + plan.tripType == 'Domestic' + ? 37 + : 40, + ), + ], + ), + ), + SizedBox(width: 10), + Expanded( + child: Container( + // color: Colors.yellow.shade50, + child: Column( children: [ - GestureDetector( - onTap: - () => _showDetails(plan.planId), - child: Container( - padding: EdgeInsets.symmetric( - horizontal: 8, - vertical: 4, - ), - decoration: BoxDecoration( - color: getStatusColor( - plan.statusValue, - ), - borderRadius: - BorderRadius.circular(8), - ), - child: Text( - plan.statusValue, - style: TextStyle( - color: getStatusTextColor( - plan.statusValue, + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + '${plan.tripTitle}', + style: TextStyle( + fontSize: 12, + fontFamily: "Inter", + fontWeight: FontWeight.bold, + ), ), - fontSize: 10, - fontWeight: FontWeight.w600, - ), + ], ), - ), + Column( + children: [ + // PlanPopupMenu( + // plan: plan, + // deletePlan: deletePlan, + // apiService: apiService, + // layoutColor: layoutColor, + // ), + PopupMenuButton( + color: Colors.white, + padding: EdgeInsets.zero, + offset: Offset(0, 30), + icon: Icon( + Icons.more_vert, + color: Color(0xFF475569), + size: 14, + ), + itemBuilder: + (context) => [ + CustomPopupMenuEntry( + child: Container( + padding: + EdgeInsets.symmetric( + horizontal: 1, + vertical: 1, + // horizontal: 8, + // vertical: 8, + ), + child: Row( + mainAxisSize: + MainAxisSize + .min, + mainAxisAlignment: + MainAxisAlignment + .center, + children: [ + IconButton( + icon: Icon( + Icons + .remove_red_eye, + color: Color( + 0xFF475569, + ), + size: 18, + ), + tooltip: + 'View The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); // Close popup manually + ApiService.viewPlan( + context, + plan.planId, + isViewMode: + true, + ); + }, + ), + if (plan.statusValue == + "Pending Approval" || + plan.statusValue == + "Partially Approved") + IconButton( + icon: Image.asset( + 'assets/images/IconsImg/edit.png', + width: 20, + height: + 15, + ), + tooltip: + 'Edit The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + ApiService.viewPlan( + context, + plan.planId, + isViewMode: + false, + ); + }, + ), + IconButton( + icon: Icon( + Icons + .cancel_rounded, + size: 18, + ), + tooltip: + 'Cancellation The Trip Details', + onPressed: () { + Navigator.pop( + context, + ); + deletePlan( + plan.planId, + ); + }, + ), + IconButton( + icon: Icon( + Icons + .download, + color: Color( + 0xFF114D8B, + ), + size: 18, + ), + tooltip: + 'Download The PDF', + onPressed: () { + Navigator.pop( + context, + ); + apiService + .getPdfDownload( + plan.planId, + ); + }, + ), + IconButton( + icon: const Icon( + Icons + .comment, + color: Color( + 0xFF475569, + ), + size: 11, + ), + tooltip: + 'Trip Comments', + onPressed: () { + showDialog( + context: + context, + builder: + ( + context, + ) => CommentModalList( + // planId: plan.planId, + planId: + plan.planId.toString(), + layoutColorForUser: + layoutColor!, + role: + "Admin", + ), + ); + }, + ), + ], + ), + ), + ), + ], + ), + ], + ), + ], ), - ], - ), - Column( - children: [ - // PlanPopupMenu( - // plan: plan, - // deletePlan: deletePlan, - // apiService: apiService, - // layoutColor: layoutColor, - // ), - PopupMenuButton( - color: Colors.white, - padding: EdgeInsets.zero, - offset: Offset(0, 30), - icon: Icon( - Icons.more_vert, - color: Color(0xFF475569), - size: 14, - ), - itemBuilder: - (context) => [ - CustomPopupMenuEntry( + + Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + + children: [ + Column( + crossAxisAlignment: + CrossAxisAlignment.start, + children: [ + Text( + plan.userName.isNotEmpty + ? '${plan.userName}' + : '${plan.travellerName}', + style: TextStyle( + fontSize: 12, + fontFamily: "Inter", + color: Colors.black87, + ), + ), + Text( + plan.employeeCode ?? + 'No Data', + style: TextStyle( + fontSize: 9, + fontFamily: "Inter", + color: Colors.black87, + ), + ), + Text( + '${_formatDate(plan.createdOn)}', + style: TextStyle( + fontSize: 10, + color: Colors.black87, + fontFamily: "Inter", + ), + ), + + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // + // ], + // ), + // Spacer(), + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // + // ], + // ), + // ], + // ), + ], + ), + Column( + children: [ + GestureDetector( + onTap: + () => _showDetails( + plan.planId, + ), child: Container( padding: EdgeInsets.symmetric( horizontal: 8, - vertical: 8, + vertical: 4, ), - child: Row( - mainAxisSize: - MainAxisSize.min, - mainAxisAlignment: - MainAxisAlignment - .center, - children: [ - IconButton( - icon: Icon( - Icons - .remove_red_eye, - color: Color( - 0xFF475569, + decoration: BoxDecoration( + color: getStatusColor( + plan.statusValue, + ), + borderRadius: + BorderRadius.circular( + 8, + ), + ), + child: Text( + plan.statusValue, + style: TextStyle( + color: + getStatusTextColor( + plan.statusValue, ), - size: 18, - ), - tooltip: - 'View The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); // Close popup manually - ApiService.viewPlan( - context, - plan.planId, - isViewMode: true, - ); - }, - ), - if (plan.statusValue == - "Pending Approval" || - plan.statusValue == - "Partially Approved") - IconButton( - icon: Image.asset( - 'assets/images/IconsImg/edit.png', - width: 20, - height: 15, - ), - tooltip: - 'Edit The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); - ApiService.viewPlan( - context, - plan.planId, - isViewMode: - false, - ); - }, - ), - IconButton( - icon: Icon( - Icons - .cancel_rounded, - size: 18, - ), - tooltip: - 'Cancellation The Trip Details', - onPressed: () { - Navigator.pop( - context, - ); - deletePlan( - plan.planId, - ); - }, - ), - IconButton( - icon: Icon( - Icons.download, - color: Color( - 0xFF114D8B, - ), - size: 18, - ), - tooltip: - 'Download The PDF', - onPressed: () { - Navigator.pop( - context, - ); - apiService - .getPdfDownload( - plan.planId, - ); - }, - ), - IconButton( - icon: const Icon( - Icons.comment, - color: Color( - 0xFF475569, - ), - size: 11, - ), - tooltip: - 'Trip Comments', - onPressed: () { - showDialog( - context: context, - builder: - ( - context, - ) => CommentModalList( - // planId: plan.planId, - planId: - plan.planId - .toString(), - layoutColorForUser: - layoutColor!, - role: - "Admin", - ), - ); - }, - ), - ], + fontSize: 10, + fontWeight: + FontWeight.w600, + ), ), ), ), ], + ), + ], ), ], ), - ], + ), ), - - SizedBox(height: 2), - // Trip Id and Trip Name - Row( - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - ' ${plan.tripTitle}', - style: TextStyle( - fontSize: 12, - fontFamily: "Inter", - fontWeight: FontWeight.bold, - ), - ), - ], - ), - ], - ), - SizedBox(height: 2), - // Type and Created On - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - ' ${plan.tripType}', - style: TextStyle( - fontSize: 9, - color: Colors.black87, - fontFamily: "Inter", - ), - ), - ], - ), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - '${_formatDate(plan.createdOn)}', - style: TextStyle( - fontSize: 9, - color: Colors.black87, - fontFamily: "Inter", - ), - ), - ], - ), - ], - ), - SizedBox(height: 3), - // Name - Row( - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - plan.userName.isNotEmpty - ? '${plan.userName}' - : '${plan.travellerName}', - style: TextStyle( - fontSize: 9, - fontFamily: "Inter", - color: Colors.black87, - ), - ), - ], - ), - Spacer(), - Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - plan.employeeCode ?? 'No Data', - style: TextStyle( - fontSize: 9, - fontFamily: "Inter", - color: Colors.black87, - ), - ), - ], - ), - ], - ), - // Actions ], ), + + // padding: EdgeInsets.symmetric(vertical: 12), + // child: Container( + // // color: Colors.yellow, + // child: Column( + // crossAxisAlignment: CrossAxisAlignment.start, + // mainAxisAlignment: MainAxisAlignment.start, + // children: [ + // // Status and Employee Code + // Row( + // mainAxisAlignment: + // MainAxisAlignment.spaceBetween, + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // GestureDetector( + // onTap: + // () => _showDetails(plan.planId), + // child: Container( + // padding: EdgeInsets.symmetric( + // horizontal: 8, + // vertical: 4, + // ), + // decoration: BoxDecoration( + // color: getStatusColor( + // plan.statusValue, + // ), + // borderRadius: + // BorderRadius.circular(8), + // ), + // child: Text( + // plan.statusValue, + // style: TextStyle( + // color: getStatusTextColor( + // plan.statusValue, + // ), + // fontSize: 10, + // fontWeight: FontWeight.w600, + // ), + // ), + // ), + // ), + // ], + // ), + // Column( + // children: [ + // // PlanPopupMenu( + // // plan: plan, + // // deletePlan: deletePlan, + // // apiService: apiService, + // // layoutColor: layoutColor, + // // ), + // PopupMenuButton( + // color: Colors.white, + // padding: EdgeInsets.zero, + // offset: Offset(0, 30), + // icon: Icon( + // Icons.more_vert, + // color: Color(0xFF475569), + // size: 14, + // ), + // itemBuilder: + // (context) => [ + // CustomPopupMenuEntry( + // child: Container( + // padding: + // EdgeInsets.symmetric( + // horizontal: 1, + // vertical: 1, + // // horizontal: 8, + // // vertical: 8, + // ), + // child: Row( + // mainAxisSize: + // MainAxisSize.min, + // mainAxisAlignment: + // MainAxisAlignment + // .center, + // children: [ + // IconButton( + // icon: Icon( + // Icons + // .remove_red_eye, + // color: Color( + // 0xFF475569, + // ), + // size: 18, + // ), + // tooltip: + // 'View The Trip Details', + // onPressed: () { + // Navigator.pop( + // context, + // ); // Close popup manually + // ApiService.viewPlan( + // context, + // plan.planId, + // isViewMode: + // true, + // ); + // }, + // ), + // if (plan.statusValue == + // "Pending Approval" || + // plan.statusValue == + // "Partially Approved") + // IconButton( + // icon: Image.asset( + // 'assets/images/IconsImg/edit.png', + // width: 20, + // height: 15, + // ), + // tooltip: + // 'Edit The Trip Details', + // onPressed: () { + // Navigator.pop( + // context, + // ); + // ApiService.viewPlan( + // context, + // plan.planId, + // isViewMode: + // false, + // ); + // }, + // ), + // IconButton( + // icon: Icon( + // Icons + // .cancel_rounded, + // size: 18, + // ), + // tooltip: + // 'Cancellation The Trip Details', + // onPressed: () { + // Navigator.pop( + // context, + // ); + // deletePlan( + // plan.planId, + // ); + // }, + // ), + // IconButton( + // icon: Icon( + // Icons.download, + // color: Color( + // 0xFF114D8B, + // ), + // size: 18, + // ), + // tooltip: + // 'Download The PDF', + // onPressed: () { + // Navigator.pop( + // context, + // ); + // apiService + // .getPdfDownload( + // plan.planId, + // ); + // }, + // ), + // IconButton( + // icon: const Icon( + // Icons.comment, + // color: Color( + // 0xFF475569, + // ), + // size: 11, + // ), + // tooltip: + // 'Trip Comments', + // onPressed: () { + // showDialog( + // context: + // context, + // builder: + // ( + // context, + // ) => CommentModalList( + // // planId: plan.planId, + // planId: + // plan.planId + // .toString(), + // layoutColorForUser: + // layoutColor!, + // role: + // "Admin", + // ), + // ); + // }, + // ), + // ], + // ), + // ), + // ), + // ], + // ), + // ], + // ), + // ], + // ), + // + // SizedBox(height: 2), + // // Trip Id and Trip Name + // Row( + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // ' ${plan.tripTitle}', + // style: TextStyle( + // fontSize: 12, + // fontFamily: "Inter", + // fontWeight: FontWeight.bold, + // ), + // ), + // ], + // ), + // ], + // ), + // SizedBox(height: 2), + // // Type and Created On + // Row( + // mainAxisAlignment: + // MainAxisAlignment.spaceBetween, + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // ' ${plan.tripType}', + // style: TextStyle( + // fontSize: 9, + // color: Colors.black87, + // fontFamily: "Inter", + // ), + // ), + // ], + // ), + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // '${_formatDate(plan.createdOn)}', + // style: TextStyle( + // fontSize: 9, + // color: Colors.black87, + // fontFamily: "Inter", + // ), + // ), + // ], + // ), + // ], + // ), + // SizedBox(height: 3), + // // Name + // Row( + // children: [ + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // plan.userName.isNotEmpty + // ? '${plan.userName}' + // : '${plan.travellerName}', + // style: TextStyle( + // fontSize: 9, + // fontFamily: "Inter", + // color: Colors.black87, + // ), + // ), + // ], + // ), + // Spacer(), + // Column( + // crossAxisAlignment: + // CrossAxisAlignment.start, + // children: [ + // Text( + // plan.employeeCode ?? 'No Data', + // style: TextStyle( + // fontSize: 9, + // fontFamily: "Inter", + // color: Colors.black87, + // ), + // ), + // ], + // ), + // ], + // ), + // // Actions + // ], + // ), + // ), ), ); }, diff --git a/lib/Screens/organization/orgSetup.dart b/lib/Screens/organization/orgSetup.dart index 43431af..5f4a590 100644 --- a/lib/Screens/organization/orgSetup.dart +++ b/lib/Screens/organization/orgSetup.dart @@ -39,6 +39,8 @@ class _OrgSetUpState extends State { List? apiAllServices; Map? selectedOrg; Color? layoutColor; + Color? layoutSecondaryColor; + Color? layoutTertiaryColor; Color? bodyColor; bool isSelected = false; @@ -112,6 +114,10 @@ class _OrgSetUpState extends State { "layout_color": "0x${layoutColor?.toARGB32().toRadixString(16).padLeft(8, '0').toUpperCase()}", + "secondary_color": + "0x${layoutSecondaryColor?.toARGB32().toRadixString(16).padLeft(8, '0').toUpperCase()}", + "tertiary_color": + "0x${layoutTertiaryColor?.toARGB32().toRadixString(16).padLeft(8, '0').toUpperCase()}", "color": "0x${bodyColor?.toARGB32().toRadixString(16).padLeft(8, '0').toUpperCase()}", @@ -181,6 +187,7 @@ class _OrgSetUpState extends State { // } String? rawLogoPath = selectedOrg?['logo']; + if (rawLogoPath != null && rawLogoPath.contains('/assets')) { const baseUrl = apiUrl; // const baseUrl = "https://apitest.tripapprovaltool.com"; @@ -202,6 +209,30 @@ class _OrgSetUpState extends State { ), ) : Colors.white; + layoutSecondaryColor = + selectedOrg?['secondary_color'] != null + ? Color( + int.parse( + selectedOrg!['secondary_color'].toString().replaceFirst( + '0x', + '', + ), + radix: 16, + ), + ) + : Colors.white; + layoutTertiaryColor = + selectedOrg?['tertiary_color'] != null + ? Color( + int.parse( + selectedOrg!['tertiary_color'].toString().replaceFirst( + '0x', + '', + ), + radix: 16, + ), + ) + : Colors.white; bodyColor = selectedOrg?['color'] != null @@ -760,29 +791,39 @@ class _OrgSetUpState extends State { // color: Color(0xFFF5F5F5), color: Colors.white, ), - padding: EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5), + padding: EdgeInsets.only( + left: 5, + right: 5, + top: 15, + bottom: 5, + ), child: SingleChildScrollView( scrollDirection: Axis.vertical, - child: isDesktop - ? Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: _buildOptions(), - ) - : SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: ConstrainedBox( // ✅ Prevent overflow by setting min width - constraints: BoxConstraints( - minWidth: MediaQuery.of(context).size.width, - ), - child: IntrinsicWidth( // ✅ Let Row size itself correctly - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: _buildOptions(), - ), - ), - ), - ), + child: + isDesktop + ? Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: _buildOptions(), + ) + : SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: ConstrainedBox( + // ✅ Prevent overflow by setting min width + constraints: BoxConstraints( + minWidth: MediaQuery.of(context).size.width, + ), + child: IntrinsicWidth( + // ✅ Let Row size itself correctly + child: Row( + crossAxisAlignment: + CrossAxisAlignment.start, + children: _buildOptions(), + ), + ), + ), + ), ), ), SizedBox(height: 15), @@ -817,9 +858,15 @@ class _OrgSetUpState extends State { initialBodyColor: bodyColor, onLayoutColorSelected: ( Color selectedLayoutColor, + Color selectedSecondaryColor, + Color selectedTeritaryColor, ) { setState(() { layoutColor = selectedLayoutColor; + layoutSecondaryColor = + selectedSecondaryColor; + layoutTertiaryColor = + selectedTeritaryColor; }); }, onBodyColorSelected: ( diff --git a/lib/Screens/organization/themeColor.dart b/lib/Screens/organization/themeColor.dart index d2b44fb..d086a44 100644 --- a/lib/Screens/organization/themeColor.dart +++ b/lib/Screens/organization/themeColor.dart @@ -4,7 +4,8 @@ class ColorThemePickerWidget extends StatefulWidget { final Color? initialLayoutColor; final Color? initialBodyColor; - final Function(Color) onLayoutColorSelected; + final Function(Color layout, Color secondaryColor, Color tertiaryColor) + onLayoutColorSelected; final Function(Color) onBodyColorSelected; const ColorThemePickerWidget({ @@ -21,6 +22,8 @@ class ColorThemePickerWidget extends StatefulWidget { class _ColorThemePickerWidgetState extends State { late Color selectedLayoutColor; + Color? selectedSecondaryColor; + Color? selectedTertiaryColor; late Color selectedBodyColor; // Layout colors @@ -36,7 +39,35 @@ class _ColorThemePickerWidgetState extends State { Color(0xFFc94b92), // rose light Color(0xFF9C27B0), // Purple Color(0xFF9B59B6), // Purple 2 - ]; + ]; + + final List layoutSecondaryColors = [ + Color(0xFF00B0FF), // Lighter Blue + Color(0xFF00ACC1), // Teal Blue + Color(0xFF43A047), // Dark Green + Color(0xFF27AE60), // Medium Emerald + Color(0xFFFFC107), // Amber (complementary to orange) + Color(0xFFFFA726), // Light orange + Color(0xFFE64A19), // Deep Orange + Color(0xFFFF4081), // Bright Pink (complementary to rose) + Color(0xFFF48FB1), // Light Pink + Color(0xFFBA68C8), // Light Purple + Color(0xFFAB47BC), // Orchid Purple + ]; + + final List layoutTertiaryColors = [ + Color(0xFF82B1FF), // Very Light Blue + Color(0xFF4DD0E1), // Lighter Teal + Color(0xFF81C784), // Light Green + Color(0xFFAAF0D1), // Pastel Mint + Color(0xFFFFE0B2), // Pale Orange + Color(0xFFFFCCBC), // Light Orange Peach + Color(0xFFFFAB91), // Light Coral + Color(0xFFF8BBD0), // Pastel Rose + Color(0xFFF8BBD0), // Pastel Pink + Color(0xFFE1BEE7), // Lavender + Color(0xFFD1C4E9), // Light Purple Grey + ]; // Body colors final List bodyThemeColors = [ @@ -63,16 +94,36 @@ class _ColorThemePickerWidgetState extends State { children: [ // Layout Color Picker GestureDetector( - onTap: () => _showColorPickerDialog( - title: "Choose Layout Color", - colors: layoutThemeColors, - onColorSelected: (color) { - setState(() { - selectedLayoutColor = color; - }); - widget.onLayoutColorSelected(color); - }, - ), + onTap: + () => _showColorPickerDialog( + title: "Choose Layout Color", + colors: layoutThemeColors, + onColorSelected: (color) { + setState(() { + selectedLayoutColor = color; + print("selectedLayoutColor - $selectedLayoutColor"); + final SelectedIndex = layoutThemeColors.indexOf(color); + print("SelectedIndexLayout - $SelectedIndex"); + + if (SelectedIndex != -1) { + final secondaryColor = + layoutSecondaryColors[SelectedIndex]; + final primaryColor = layoutTertiaryColors[SelectedIndex]; + + selectedSecondaryColor = secondaryColor; + selectedTertiaryColor = primaryColor; + + print("selectedSecondaryColor - $selectedSecondaryColor"); + print("selectedPrimaryColor - $selectedTertiaryColor"); + } + }); + widget.onLayoutColorSelected( + color, + selectedSecondaryColor!, + selectedTertiaryColor!, + ); + }, + ), child: _buildColorBox( selectedLayoutColor ?? Colors.grey.shade300, Icons.palette, @@ -179,24 +230,37 @@ class _ColorThemePickerWidgetState extends State { showDialog( context: context, - builder: (context) => AlertDialog( - title: Text(title), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: firstRow.map((color) => _buildColorCircle(color, onColorSelected)).toList(), + builder: + (context) => AlertDialog( + title: Text(title), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: + firstRow + .map( + (color) => + _buildColorCircle(color, onColorSelected), + ) + .toList(), + ), + if (secondRow.isNotEmpty) SizedBox(height: 10), + if (secondRow.isNotEmpty) + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: + secondRow + .map( + (color) => + _buildColorCircle(color, onColorSelected), + ) + .toList(), + ), + ], ), - if (secondRow.isNotEmpty) SizedBox(height: 10), - if (secondRow.isNotEmpty) - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: secondRow.map((color) => _buildColorCircle(color, onColorSelected)).toList(), - ), - ], - ), - ), + ), ); } @@ -215,5 +279,4 @@ class _ColorThemePickerWidgetState extends State { ), ); } - } diff --git a/lib/Screens/userManagement/create_user/personal_details.dart b/lib/Screens/userManagement/create_user/personal_details.dart index 7de3dbf..619395b 100644 --- a/lib/Screens/userManagement/create_user/personal_details.dart +++ b/lib/Screens/userManagement/create_user/personal_details.dart @@ -103,7 +103,6 @@ class PersonalDetailsState extends State { bool _postalCodeFocus = false; bool _roleIdFocus = false; - late bool isTravelAgent = false; String? selectedTab; @@ -158,7 +157,7 @@ class PersonalDetailsState extends State { Color? bodyColor; final Map controllers = {}; - Map errorMessages2 = {}; + Map errorMessages = {}; @override void initState() { @@ -180,20 +179,27 @@ class PersonalDetailsState extends State { print("selectedServiceIdsAPI - $selectedServiceIds"); - - _addFocusListener(_fnameFocusNode, (focus) => _fnameFocus = focus); - _addFocusListener(_lnameFocusNode, (focus) => _lnameFocus = focus); - _addFocusListener(_emailFocusNode, (focus) => _emailFocus = focus); - _addFocusListener(_passwordFocusNode, (focus) => _passwordFocus = focus); - _addFocusListener(_dobFocusNode, (focus) => _dobFocus = focus); - _addFocusListener(_genderFocusNode, (focus) => _genderFocus = focus); - _addFocusListener(_mobileNumberFocusNode, (focus) => _mobileNumberFocus = focus); - _addFocusListener(_alternateMobileFocusNode, (focus) => _alternateMobileFocus = focus); - _addFocusListener(_addressFocusNode, (focus) => _addressFocus = focus); - _addFocusListener(_countryFocusNode, (focus) => _countryFocus = focus); - _addFocusListener(_postalCodeFocusNode, (focus) => _postalCodeFocus = focus); - _addFocusListener(_roleIdFocusNode, (focus) => _roleIdFocus = focus); - + _addFocusListener(_fnameFocusNode, (focus) => _fnameFocus = focus); + _addFocusListener(_lnameFocusNode, (focus) => _lnameFocus = focus); + _addFocusListener(_emailFocusNode, (focus) => _emailFocus = focus); + _addFocusListener(_passwordFocusNode, (focus) => _passwordFocus = focus); + _addFocusListener(_dobFocusNode, (focus) => _dobFocus = focus); + _addFocusListener(_genderFocusNode, (focus) => _genderFocus = focus); + _addFocusListener( + _mobileNumberFocusNode, + (focus) => _mobileNumberFocus = focus, + ); + _addFocusListener( + _alternateMobileFocusNode, + (focus) => _alternateMobileFocus = focus, + ); + _addFocusListener(_addressFocusNode, (focus) => _addressFocus = focus); + _addFocusListener(_countryFocusNode, (focus) => _countryFocus = focus); + _addFocusListener( + _postalCodeFocusNode, + (focus) => _postalCodeFocus = focus, + ); + _addFocusListener(_roleIdFocusNode, (focus) => _roleIdFocus = focus); WidgetsBinding.instance.addPostFrameCallback((_) { loadAllServices(); @@ -233,7 +239,7 @@ class PersonalDetailsState extends State { userId, ); if (response.isNotEmpty) { - _clearError(field); + // _clearError(field); widget.errorMessages[field] = response['message'] ?? "$label Already Exists"; print("Duplicate found: ${response['message']}"); @@ -1052,85 +1058,89 @@ class PersonalDetailsState extends State { onTap: () { _genderFocusNode?.requestFocus(); }, - child: DropdownSearch( - selectedItem: selectedGender, - enabled: !widget.isViewMode, + child: DropdownSearch( + selectedItem: selectedGender, + enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: false, // Set true if you want search - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 200), - itemBuilder: - (context, item, isSelected) => Container( - color: Colors.white, - padding: EdgeInsets.symmetric( + popupProps: PopupProps.menu( + showSearchBox: false, // Set true if you want search + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 200), + itemBuilder: + (context, item, isSelected) => Container( + color: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + ), + items: genderOptions, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_genderFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_genderFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: (layoutColor ?? Colors.grey), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( horizontal: 10, - vertical: 6, + // vertical: 1, ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + // contentPadding: EdgeInsets.symmetric(horizontal: 1), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select Gender", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), ), - ), - ), - items: genderOptions, - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(5), - borderSide: BorderSide( - color: - (_genderFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_genderFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 10, - // vertical: 1, - ), - // contentPadding: EdgeInsets.symmetric(horizontal: 1), + onChanged: + widget.isViewMode + ? null + : (String? newValue) { + setState(() { + selectedGender = newValue; + print("selectedGender - $selectedGender"); + }); + widget.onGenderChanged?.call(newValue); + }, ), ), - dropdownBuilder: - (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select Gender", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ), - onChanged: - widget.isViewMode - ? null - : (String? newValue) { - setState(() { - selectedGender = newValue; - print("selectedGender - $selectedGender"); - }); - widget.onGenderChanged?.call(newValue); - }, - ),),), + ), ), ), ], @@ -1187,8 +1197,7 @@ class PersonalDetailsState extends State { isDesktop: widget.isDesktop, child: SizedBox( height: 40, - child: - Focus( + child: Focus( focusNode: _dobFocusNode, onKeyEvent: (FocusNode node, KeyEvent event) { // Only act on KeyDown and when Enter is pressed @@ -1225,7 +1234,10 @@ class PersonalDetailsState extends State { child: TextField( controller: widget.controllers["dob"], readOnly: true, - style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), decoration: InputDecoration( labelText: "Select Date", labelStyle: GoogleFonts.poppins( @@ -1247,46 +1259,46 @@ class PersonalDetailsState extends State { ), ), // GestureDetector( - // onTap: - // widget.isViewMode - // ? null - // : () async { - // await _selectCheckDateOfBirth(context); - // if (widget.controllers["dob"]!.text.isNotEmpty) { - // setState(() { - // // errorMessages.remove("start_date"); - // }); - // // Delay re-focusing the DOB field slightly - // Future.delayed(Duration(milliseconds: 100), () { - // _dobFocusNode?.requestFocus(); - // }); - // } - // }, - // child: AbsorbPointer( - // child: TextField( - // controller: widget.controllers["dob"], - // focusNode:_dobFocusNode, - // readOnly: true, - // 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), - // ), - // ), - // ), - // ), - // ), + // onTap: + // widget.isViewMode + // ? null + // : () async { + // await _selectCheckDateOfBirth(context); + // if (widget.controllers["dob"]!.text.isNotEmpty) { + // setState(() { + // // errorMessages.remove("start_date"); + // }); + // // Delay re-focusing the DOB field slightly + // Future.delayed(Duration(milliseconds: 100), () { + // _dobFocusNode?.requestFocus(); + // }); + // } + // }, + // child: AbsorbPointer( + // child: TextField( + // controller: widget.controllers["dob"], + // focusNode:_dobFocusNode, + // readOnly: true, + // 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), + // ), + // ), + // ), + // ), + // ), ), ), ], @@ -1477,7 +1489,7 @@ class PersonalDetailsState extends State { countryMap = { for (var country in countryList) (country['country_code'] ?? ''): - '${country['country_name'] ?? ''} (${country['country_code'] ?? ''})', + '${country['country_name'] ?? ''} (${country['country_code'] ?? ''})', }; // Extract only country codes for processing @@ -1503,125 +1515,137 @@ class PersonalDetailsState extends State { isDesktop: widget.isDesktop, child: SizedBox( height: 40, - width: double.infinity, - child: Focus( - focusNode: _countryFocusNode, - onFocusChange: (hasFocus) { - setState(() { - _countryFocus = hasFocus; - }); + width: double.infinity, + child: Focus( + focusNode: _countryFocusNode, + onFocusChange: (hasFocus) { + setState(() { + _countryFocus = hasFocus; + }); + }, + child: GestureDetector( + onTap: () { + // Request focus when user taps + _countryFocusNode?.requestFocus(); }, - child: GestureDetector( - onTap: () { - // Request focus when user taps - _countryFocusNode?.requestFocus(); - }, - child: DropdownSearch( - selectedItem: countryMap[selectedCountry], - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, // Enables search functionality - fit: FlexFit.loose, // Allows flexible height - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Container( - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + child: DropdownSearch( + selectedItem: countryMap[selectedCountry], + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, // Enables search functionality + fit: FlexFit.loose, // Allows flexible height + menuProps: const MenuProps(backgroundColor: Colors.white), + itemBuilder: + (context, item, isSelected) => Container( + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + constraints: BoxConstraints(maxHeight: 180), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Country...", + contentPadding: EdgeInsets.symmetric( + horizontal: 3, + vertical: 3, + ), ), ), - constraints: BoxConstraints(maxHeight: 180), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Country...", - contentPadding: EdgeInsets.symmetric(horizontal: 3,vertical: 3), ), + items: countryMap.values.toList(), + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(horizontal: 1), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(8), + borderSide: BorderSide( + color: + (_countryFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_countryFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: (layoutColor ?? Colors.grey), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 10.0, + vertical: 8.0, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + // Center-align selected item + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select Country", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ), + + // onChanged: widget.isViewMode + // ? null + // : (String? newValue) { + // setState(() { + // // Find the country_code based on selected country_name + // selectedCountry = countryMap.entries + // .firstWhere((entry) => entry.value == newValue) + // .key; + // + // // if (selectedCountry!.isNotEmpty) { + // // errorMessages.remove("country_code"); + // // } + // }); + // widget.onCountryChanged?.call(newValue); + // }, + onChanged: + widget.isViewMode + ? null + : (String? newValue) { + if (newValue == null) return; + + final countryCode = + countryMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + + setState(() { + selectedCountry = countryCode; + }); + + widget.onCountryChanged?.call( + countryCode, + ); // ✅ send code not name + }, ), ), - items: countryMap.values.toList(), - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(horizontal: 1), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8), - borderSide: BorderSide( - color: - (_countryFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_countryFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide( - color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 8.0), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - // Center-align selected item - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select Country", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ), - - // onChanged: widget.isViewMode - // ? null - // : (String? newValue) { - // setState(() { - // // Find the country_code based on selected country_name - // selectedCountry = countryMap.entries - // .firstWhere((entry) => entry.value == newValue) - // .key; - // - // // if (selectedCountry!.isNotEmpty) { - // // errorMessages.remove("country_code"); - // // } - // }); - // widget.onCountryChanged?.call(newValue); - // }, - onChanged: - widget.isViewMode - ? null - : (String? newValue) { - if (newValue == null) return; - - final countryCode = - countryMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - - setState(() { - selectedCountry = countryCode; - }); - - widget.onCountryChanged?.call( - countryCode, - ); // ✅ send code not name - }, - ),),) + ), ), ), ], @@ -1780,99 +1804,107 @@ class PersonalDetailsState extends State { // Request focus when user taps _roleIdFocusNode?.requestFocus(); }, - child: DropdownSearch( - selectedItem: selectedRole != null ? roleMap[selectedRole] : null, - enabled: !widget.isViewMode, - popupProps: PopupProps.menu( - showSearchBox: true, - fit: FlexFit.loose, - constraints: BoxConstraints(maxHeight: 250), - menuProps: const MenuProps(backgroundColor: Colors.white), - itemBuilder: - (context, item, isSelected) => Container( - color: Colors.white, - padding: EdgeInsets.symmetric( - horizontal: 10, - vertical: 6, - ), - child: Text( - item, - style: GoogleFonts.poppins(fontSize: 11.5), + child: DropdownSearch( + selectedItem: + selectedRole != null ? roleMap[selectedRole] : null, + enabled: !widget.isViewMode, + popupProps: PopupProps.menu( + showSearchBox: true, + fit: FlexFit.loose, + constraints: BoxConstraints(maxHeight: 250), + menuProps: const MenuProps(backgroundColor: Colors.white), + itemBuilder: + (context, item, isSelected) => Container( + color: Colors.white, + padding: EdgeInsets.symmetric( + horizontal: 10, + vertical: 6, + ), + child: Text( + item, + style: GoogleFonts.poppins(fontSize: 11.5), + ), + ), + searchFieldProps: TextFieldProps( + decoration: InputDecoration( + hintText: "Search Role...", + contentPadding: EdgeInsets.symmetric(horizontal: 10), ), ), - searchFieldProps: TextFieldProps( - decoration: InputDecoration( - hintText: "Search Role...", - contentPadding: EdgeInsets.symmetric(horizontal: 10), ), + items: roleNames, + dropdownDecoratorProps: DropDownDecoratorProps( + dropdownSearchDecoration: InputDecoration( + // border: InputBorder.none, + // contentPadding: EdgeInsets.symmetric(horizontal: 1), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(5), + borderSide: BorderSide( + color: + (_roleIdFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + width: 0.5, + ), + ), + enabledBorder: OutlineInputBorder( + borderSide: BorderSide( + color: + (_roleIdFocus) + ? (layoutColor ?? Colors.blue) + : Colors.white, + // : const Color(0xFFD6D5E6), + width: 0.5, + // const Color(0xFFD6D5E6), + ), + ), + focusedBorder: OutlineInputBorder( + borderSide: BorderSide( + color: (layoutColor ?? Colors.grey), + width: 0.5, + ), + ), + contentPadding: EdgeInsets.symmetric( + horizontal: 8, + vertical: 1, + ), + ), + ), + dropdownBuilder: + (context, selectedItem) => Align( + alignment: Alignment.centerLeft, + child: Text( + selectedItem ?? "Select Role", + style: GoogleFonts.poppins( + fontSize: 12, + color: Colors.black, + ), + ), + ), + onChanged: + widget.isViewMode + ? null + : (String? newValue) { + widget.errorMessages.remove("role_id"); + if (newValue == null) return; + final selectedKey = + roleMap.entries + .firstWhere( + (entry) => entry.value == newValue, + ) + .key; + + setState(() { + selectedRole = selectedKey; + isTravelAgent = selectedKey == "5"; + }); + + widget.onUserTypeChanged?.call(isTravelAgent); + widget.onRoleChanged?.call(selectedKey); + }, ), ), - items: roleNames, - dropdownDecoratorProps: DropDownDecoratorProps( - dropdownSearchDecoration: InputDecoration( - // border: InputBorder.none, - // contentPadding: EdgeInsets.symmetric(horizontal: 1), - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(5), - borderSide: BorderSide( - color: - (_roleIdFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - width: 0.5, - ), - ), - enabledBorder: OutlineInputBorder( - borderSide: BorderSide( - color: - (_roleIdFocus) - ? (layoutColor ?? Colors.blue) - : Colors.white, - // : const Color(0xFFD6D5E6), - width: 0.5, - // const Color(0xFFD6D5E6), - ), - ), - focusedBorder: OutlineInputBorder( - borderSide: BorderSide(color : (layoutColor ?? Colors.grey), width: 0.5), - ), - contentPadding: EdgeInsets.symmetric( - horizontal: 8, - vertical: 1, - ), - ), - ), - dropdownBuilder: - (context, selectedItem) => Align( - alignment: Alignment.centerLeft, - child: Text( - selectedItem ?? "Select Role", - style: GoogleFonts.poppins( - fontSize: 12, - color: Colors.black, - ), - ), - ), - onChanged: - widget.isViewMode - ? null - : (String? newValue) { - widget.errorMessages.remove("role_id"); - if (newValue == null) return; - final selectedKey = - roleMap.entries - .firstWhere((entry) => entry.value == newValue) - .key; - - setState(() { - selectedRole = selectedKey; - isTravelAgent = selectedKey == "5"; - }); - - widget.onUserTypeChanged?.call(isTravelAgent); - widget.onRoleChanged?.call(selectedKey); - }, - ),),), + ), ), ), if (widget.errorMessages["role_id"] != null) ...[