UI_ADDITIONAL_COLOR, UI_ALLTRIPS_CARD

This commit is contained in:
venbaittech 2025-07-18 09:47:33 +05:30
parent bc8968f9c5
commit 66d62ca8f8
4 changed files with 1126 additions and 661 deletions

View File

@ -503,7 +503,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
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<ListAllPlans> {
// 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<int>(
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<int>(
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<int>(
// 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
// ],
// ),
// ),
),
);
},

View File

@ -39,6 +39,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
List<dynamic>? apiAllServices;
Map<String, dynamic>? selectedOrg;
Color? layoutColor;
Color? layoutSecondaryColor;
Color? layoutTertiaryColor;
Color? bodyColor;
bool isSelected = false;
@ -112,6 +114,10 @@ class _OrgSetUpState extends State<OrgSetUp> {
"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<OrgSetUp> {
// }
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<OrgSetUp> {
),
)
: 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<OrgSetUp> {
// 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<OrgSetUp> {
initialBodyColor: bodyColor,
onLayoutColorSelected: (
Color selectedLayoutColor,
Color selectedSecondaryColor,
Color selectedTeritaryColor,
) {
setState(() {
layoutColor = selectedLayoutColor;
layoutSecondaryColor =
selectedSecondaryColor;
layoutTertiaryColor =
selectedTeritaryColor;
});
},
onBodyColorSelected: (

View File

@ -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<ColorThemePickerWidget> {
late Color selectedLayoutColor;
Color? selectedSecondaryColor;
Color? selectedTertiaryColor;
late Color selectedBodyColor;
// Layout colors
@ -36,7 +39,35 @@ class _ColorThemePickerWidgetState extends State<ColorThemePickerWidget> {
Color(0xFFc94b92), // rose light
Color(0xFF9C27B0), // Purple
Color(0xFF9B59B6), // Purple 2
];
];
final List<Color> 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<Color> 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<Color> bodyThemeColors = [
@ -63,16 +94,36 @@ class _ColorThemePickerWidgetState extends State<ColorThemePickerWidget> {
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<ColorThemePickerWidget> {
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<ColorThemePickerWidget> {
),
);
}
}

View File

@ -103,7 +103,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
bool _postalCodeFocus = false;
bool _roleIdFocus = false;
late bool isTravelAgent = false;
String? selectedTab;
@ -158,7 +157,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
Color? bodyColor;
final Map<String, TextEditingController> controllers = {};
Map<String, String> errorMessages2 = {};
Map<String, String> errorMessages = {};
@override
void initState() {
@ -180,20 +179,27 @@ class PersonalDetailsState extends State<PersonalDetails> {
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<PersonalDetails> {
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<PersonalDetails> {
onTap: () {
_genderFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: selectedGender,
enabled: !widget.isViewMode,
child: DropdownSearch<String>(
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<PersonalDetails> {
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<PersonalDetails> {
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<PersonalDetails> {
),
),
// 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<PersonalDetails> {
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<PersonalDetails> {
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<String>(
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<String>(
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<PersonalDetails> {
// Request focus when user taps
_roleIdFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
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<String>(
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) ...[