user mangement bugs

This commit is contained in:
venbaittech 2025-06-05 12:40:16 +05:30
parent 7c9968c159
commit b246c79789
15 changed files with 4932 additions and 3769 deletions

File diff suppressed because it is too large Load Diff

View File

@ -156,6 +156,8 @@ class _LoginWidgetState extends State<LoginWidget> {
backgroundColor: Colors.red, backgroundColor: Colors.red,
), ),
); );
_emailController.clear();
_passwordController.clear();
// Fluttertoast.showToast( // Fluttertoast.showToast(
// msg: "Login Failed: $errorMessage", // msg: "Login Failed: $errorMessage",
// toastLength: Toast.LENGTH_LONG, // toastLength: Toast.LENGTH_LONG,

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,6 @@ import '../../utils/auth_utils.dart';
import '../../utils/pagination.dart'; import '../../utils/pagination.dart';
import 'groupDetails.dart'; import 'groupDetails.dart';
class GroupList extends StatefulWidget { class GroupList extends StatefulWidget {
@override @override
_GroupListState createState() => _GroupListState(); _GroupListState createState() => _GroupListState();
@ -39,7 +37,6 @@ class _GroupListState extends State<GroupList> {
List filteredGroups = []; List filteredGroups = [];
TextEditingController searchController = TextEditingController(); TextEditingController searchController = TextEditingController();
int currentPage = 0; int currentPage = 0;
int itemsPerPage = 10; int itemsPerPage = 10;
@ -71,14 +68,14 @@ class _GroupListState extends State<GroupList> {
setState(() { setState(() {
layoutColor = layoutColor =
layoutString != null layoutString != null
? Color(int.parse(layoutString)) ? Color(int.parse(layoutString))
: Colors.redAccent; : Colors.redAccent;
bodyColor = bodyColor =
bodyStringColor != null bodyStringColor != null
? Color(int.parse(bodyStringColor)) ? Color(int.parse(bodyStringColor))
: Colors.white; : Colors.white;
}); });
} }
@ -87,15 +84,11 @@ class _GroupListState extends State<GroupList> {
return prefs.getString('auth_token'); return prefs.getString('auth_token');
} }
Future<List<dynamic>> fetchGroups() async { Future<List<dynamic>> fetchGroups() async {
final result = await apiService.fetchAllGroup(); final result = await apiService.fetchAllGroup();
return result; // Returning raw JSON list return result; // Returning raw JSON list
} }
Future<void> loadAllGroups() async { Future<void> loadAllGroups() async {
try { try {
final result = await apiService.fetchAllGroup(); final result = await apiService.fetchAllGroup();
@ -116,14 +109,21 @@ class _GroupListState extends State<GroupList> {
filteredGroups = filteredGroups =
allGroups.where((group) { allGroups.where((group) {
return (group['name']?.toLowerCase().contains(lowerQuery) ?? return (group['name']?.toLowerCase().contains(lowerQuery) ??
false) ||
(group['domestic_policy_name']?.toLowerCase().contains(lowerQuery) ??
false)
(group['international_policy_name']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(group['domestic_policy_name']?.toLowerCase().contains(
lowerQuery,
) ??
false)(
group['international_policy_name']?.toLowerCase().contains(
lowerQuery,
) ??
false,
) ||
(group['description']?.toLowerCase().contains(lowerQuery) ?? (group['description']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(group['is_active']?.toLowerCase().contains(lowerQuery) ?? false);}).toList(); (group['is_active']?.toLowerCase().contains(lowerQuery) ??
false);
}).toList();
currentPage = 0; currentPage = 0;
}); });
@ -131,10 +131,10 @@ class _GroupListState extends State<GroupList> {
} }
void handleActiveStatus( void handleActiveStatus(
Map<String, dynamic> groupData, Map<String, dynamic> groupData,
String groupId, String groupId,
String currentStatus, String currentStatus,
) async { ) async {
print("Toggling group status - $groupId (Current: $currentStatus)"); print("Toggling group status - $groupId (Current: $currentStatus)");
final String apiUrlData = final String apiUrlData =
@ -159,7 +159,7 @@ class _GroupListState extends State<GroupList> {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
body: jsonEncode({ body: jsonEncode({
"is_active": newStatus // Set new status dynamically "is_active": newStatus, // Set new status dynamically
}), }),
); );
@ -189,7 +189,6 @@ class _GroupListState extends State<GroupList> {
loadAllGroups(); loadAllGroups();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder( return ResponsiveBuilder(
@ -203,21 +202,17 @@ class _GroupListState extends State<GroupList> {
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: padding:
isDesktop isDesktop
? EdgeInsets.symmetric( ? EdgeInsets.symmetric(
horizontal: horizontal:
MediaQuery.of(context).size.width * MediaQuery.of(context).size.width *
0.1, // 30% of screen width as horizontal padding 0.1, // 30% of screen width as horizontal padding
vertical: vertical:
MediaQuery.of(context).size.height * MediaQuery.of(context).size.height *
0, // 5% of screen height as vertical padding 0, // 5% of screen height as vertical padding
) )
: EdgeInsets.all(0), : EdgeInsets.all(0),
child: Row( child: Row(children: [Expanded(child: buildGroupList(isDesktop))]),
children: [
Expanded(child: buildGroupList(isDesktop)),
],
),
), ),
); );
}, },
@ -250,9 +245,9 @@ class _GroupListState extends State<GroupList> {
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0), // : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
// padding: const EdgeInsets.all(10), // padding: const EdgeInsets.all(10),
height: height:
isDesktop isDesktop
? MediaQuery.of(context).size.height * 0.98 ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height, : MediaQuery.of(context).size.height,
child: Padding( child: Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
@ -342,23 +337,22 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
onPressed: () async { onPressed: () async {
// List<dynamic> groups = await futureGroups; // List<dynamic> groups = await futureGroups;
// context.go('/CreateGroup'); // context.go('/CreateGroup');
showDialog( showDialog(
context: context, context: context,
builder: (context) => GroupData( builder:
isDesktop: isDesktop, (context) => GroupData(
groupId: null, isDesktop: isDesktop,
layoutColor: layoutColor!, groupId: null,
fetchGetGroup: refreshData layoutColor: layoutColor!,
), fetchGetGroup: refreshData,
); ),
);
}, },
child: Row( child: Row(
mainAxisSize: mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely MainAxisSize.min, // Ensures content fits nicely
children: [ children: [
Text( Text(
"Add New Group", "Add New Group",
@ -382,49 +376,49 @@ class _GroupListState extends State<GroupList> {
isDesktop isDesktop
? SizedBox.shrink() ? SizedBox.shrink()
: Row( : Row(
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Container( Container(
width: MediaQuery.of(context).size.width * 0.8, width: MediaQuery.of(context).size.width * 0.8,
height: 35, height: 35,
child: TextField( child: TextField(
controller: searchController, controller: searchController,
onChanged: filterGroups, onChanged: filterGroups,
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search for a Group", hintText: "Search for a Group",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, fontSize: 12,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
), ),
prefixIcon: Icon( prefixIcon: Icon(
Icons.search, Icons.search,
color: Color(0xFF9E9DBD), color: Color(0xFF9E9DBD),
size: 18, size: 18,
), ),
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade200, color: Colors.grey.shade200,
width: 0.5, width: 0.5,
), ),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
borderSide: BorderSide( borderSide: BorderSide(
color: Colors.grey.shade300, color: Colors.grey.shade300,
width: 1, width: 1,
),
),
), ),
style: GoogleFonts.poppins(fontSize: 12),
), ),
), ),
style: GoogleFonts.poppins(fontSize: 12), // SizedBox(width: 16),
), ],
), ),
// SizedBox(width: 16),
],
),
const SizedBox(height: 10), const SizedBox(height: 10),
FutureBuilder<List<dynamic>>( FutureBuilder<List<dynamic>>(
future: futureGroups, future: futureGroups,
@ -467,7 +461,7 @@ class _GroupListState extends State<GroupList> {
} }
List<dynamic> groups = List<dynamic> groups =
filteredGroups.isNotEmpty ? filteredGroups : allGroups; filteredGroups.isNotEmpty ? filteredGroups : allGroups;
groups.sort((a, b) { groups.sort((a, b) {
DateTime dateA = DateTime.parse(a['created_on']); DateTime dateA = DateTime.parse(a['created_on']);
@ -477,10 +471,10 @@ class _GroupListState extends State<GroupList> {
}); });
List paginatedGroup = List paginatedGroup =
groups groups
.skip(currentPage * itemsPerPage) .skip(currentPage * itemsPerPage)
.take(itemsPerPage) .take(itemsPerPage)
.toList(); .toList();
Widget table = LayoutBuilder( Widget table = LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
@ -554,128 +548,146 @@ class _GroupListState extends State<GroupList> {
), ),
], ],
rows: rows:
paginatedGroup.map((group) { paginatedGroup.map((group) {
String groupId = String groupId =
group['group_id'].toString(); // Get group ID group['group_id']
bool isSelected = selectedGroupId == groupId; .toString(); // Get group ID
bool isSelected = selectedGroupId == groupId;
return DataRow( return DataRow(
cells: [ cells: [
DataCell( DataCell(
Text( Text(
"${group['name'] ?? ''}", "${group['name'] ?? ''}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
),
),
), ),
), DataCell(
), Text(
DataCell( "${group['domestic_policy_name'] ?? 'N/A'}",
Text("${group['domestic_policy_name'] ?? 'N/A'}", style: TextStyle(
style: TextStyle( fontSize: 13,
fontSize: 13, fontFamily: "Inter",
fontFamily: "Inter", ),
),
), ),
), DataCell(
), Text(
DataCell( "${group['international_policy_name'] ?? 'N/A'}",
Text( style: TextStyle(
"${group['international_policy_name'] ?? 'N/A'}", fontSize: 13,
style: TextStyle( fontFamily: "Inter",
fontSize: 13, ),
fontFamily: "Inter", ),
), ),
), DataCell(
), Text(
DataCell( "${group['description'] ?? 'N/A'}",
Text( style: TextStyle(
"${group['description'] ?? 'N/A'}", fontSize: 13,
style: TextStyle( fontFamily: "Inter",
fontSize: 13, ),
fontFamily: "Inter", ),
), ),
), DataCell(
), Text(
DataCell(
Text(
group['is_active'] == "1"
? "Active"
: "Inactive",
style: TextStyle(
color:
group['is_active'] == "1" group['is_active'] == "1"
? Colors.green ? "Active"
: Colors.grey, : "Inactive",
fontFamily: "Inter", style: TextStyle(
fontWeight: FontWeight.w400, color:
group['is_active'] == "1"
? Colors.green
: Colors.grey,
fontFamily: "Inter",
fontWeight: FontWeight.w400,
),
), ),
), ),
), DataCell(
DataCell( Row(
Row( mainAxisAlignment:
mainAxisAlignment: MainAxisAlignment.start, MainAxisAlignment.start,
children: [ children: [
GestureDetector( GestureDetector(
onTap: () async { onTap: () async {
if (group['group_id'] != null) { if (group['group_id'] != null) {
final newGroupID = int.tryParse( final newGroupID = int.tryParse(
group['group_id'].toString()); group['group_id'].toString(),
if (newGroupID != null) { );
final data = await apiService.getGroupDetailsFind( if (newGroupID != null) {
newGroupID); // Always an int final data = await apiService
showDialog( .getGroupDetailsFind(
context: context, newGroupID,
builder: (context) => ); // Always an int
GroupData( showDialog(
isDesktop: isDesktop, context: context,
groupId: newGroupID, builder:
// Pass the ID (context) => GroupData(
groupData: data, isDesktop: isDesktop,
layoutColor: layoutColor!, groupId: newGroupID,
fetchGetGroup: refreshData // Pass the ID
), groupData: data,
layoutColor:
layoutColor!,
fetchGetGroup:
refreshData,
),
);
}
} else {
print(
"something went wrong check properly",
);
}
},
// onTap: () {
// context.go("/CreateGroup", extra: group);
// },
child: Tooltip(
message: 'Edit Group Details',
child: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15,
),
),
),
SizedBox(width: 5),
GestureDetector(
onTap: () {
final idStr = group['group_id'];
final id = int.tryParse(
idStr.toString(),
); );
}
} else {
print("something went wrong check properly");
}
},
// onTap: () { if (id == null) {
// context.go("/CreateGroup", extra: group); print("group_id is null");
// }, return;
child: Tooltip( }
message: 'Edit Group Details', final status = group['is_active'];
child: Image.asset('assets/images/IconsImg/edit.png', // print("GroupId : ${group['group_id']} ");
width: 20, height: 15), ), deleteGroup(group, id, status);
},
child: Tooltip(
message: 'Delete Group Details',
child: Image.asset(
'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
),
],
), ),
SizedBox( ),
width: 5, ],
), );
GestureDetector( }).toList(),
onTap: () {
final idStr = group['group_id'];
final id = int.tryParse(idStr.toString());
if (id == null) {
print("group_id is null");
return;
}
final status = group['is_active'];
// print("GroupId : ${group['group_id']} ");
deleteGroup(group, id, status);
},
child: Tooltip(
message: 'Delete Group Details',
child: Image.asset('assets/images/IconsImg/delete.png',
width: 20, height: 15),),
),
],
),
),
],
);
}).toList(),
), ),
); );
}, },
@ -688,7 +700,10 @@ class _GroupListState extends State<GroupList> {
return Card( return Card(
color: Colors.white, color: Colors.white,
margin: EdgeInsets.symmetric(horizontal: 12, vertical: 6), margin: EdgeInsets.symmetric(
horizontal: 12,
vertical: 6,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
@ -700,7 +715,8 @@ class _GroupListState extends State<GroupList> {
children: [ children: [
// Row 1: Policy Name and Actions // Row 1: Policy Name and Actions
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: RichText( child: RichText(
@ -718,11 +734,12 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['name'] ?? 'N/A'}", text:
"${object['name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
@ -736,42 +753,54 @@ class _GroupListState extends State<GroupList> {
onTap: () async { onTap: () async {
if (object['group_id'] != null) { if (object['group_id'] != null) {
final newGroupID = int.tryParse( final newGroupID = int.tryParse(
object['group_id'].toString()); object['group_id'].toString(),
);
if (newGroupID != null) { if (newGroupID != null) {
final data = await apiService.getGroupDetailsFind( final data = await apiService
newGroupID); // Always an int .getGroupDetailsFind(
newGroupID,
); // Always an int
showDialog( showDialog(
context: context, context: context,
builder: (context) => builder:
GroupData( (context) => GroupData(
isDesktop: isDesktop, isDesktop: isDesktop,
groupId: newGroupID, groupId: newGroupID,
// Pass the ID // Pass the ID
groupData: data, groupData: data,
layoutColor: layoutColor!, layoutColor:
fetchGetGroup: refreshData layoutColor!,
fetchGetGroup:
refreshData,
), ),
); );
} }
} else { } else {
print("something went wrong check properly"); print(
"something went wrong check properly",
);
} }
}, },
// onTap: () { // onTap: () {
// context.go("/CreateGroup", extra: group); // context.go("/CreateGroup", extra: group);
// }, // },
child: Tooltip( message: 'Edit Group Details', child: Tooltip(
child: Image.asset('assets/images/IconsImg/edit.png', message: 'Edit Group Details',
width: 20, height: 15),), child: Image.asset(
), 'assets/images/IconsImg/edit.png',
SizedBox( width: 20,
width: 5, height: 15,
),
),
), ),
SizedBox(width: 5),
GestureDetector( GestureDetector(
onTap: () { onTap: () {
final idStr = object['group_id']; final idStr = object['group_id'];
final id = int.tryParse(idStr.toString()); final id = int.tryParse(
idStr.toString(),
);
if (id == null) { if (id == null) {
print("group_id is null"); print("group_id is null");
@ -783,8 +812,12 @@ class _GroupListState extends State<GroupList> {
}, },
child: Tooltip( child: Tooltip(
message: 'Edit Group Details', message: 'Edit Group Details',
child: Image.asset('assets/images/IconsImg/delete.png', child: Image.asset(
width: 20, height: 15),), 'assets/images/IconsImg/delete.png',
width: 20,
height: 15,
),
),
), ),
], ],
), ),
@ -792,7 +825,6 @@ class _GroupListState extends State<GroupList> {
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 2: // Row 2:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -809,18 +841,19 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['domestic_policy_name'] ?? 'N/A'}", text:
"${object['domestic_policy_name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
), ),
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 3: // Row 3:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -837,18 +870,18 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['international_policy_name']}", text:
"${object['international_policy_name'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
), ),
), ),
SizedBox(height: 8), // Spacing SizedBox(height: 8), // Spacing
// Row 4: // Row 4:
RichText( RichText(
text: TextSpan( text: TextSpan(
@ -865,11 +898,12 @@ class _GroupListState extends State<GroupList> {
), ),
), ),
TextSpan( TextSpan(
text: "${object['description'] ?? 'N/A'}", text:
"${object['description'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.normal fontWeight: FontWeight.normal,
), ),
), ),
], ],
@ -889,12 +923,12 @@ class _GroupListState extends State<GroupList> {
children: [ children: [
Expanded( Expanded(
child: child:
isDesktop isDesktop
? SingleChildScrollView( ? SingleChildScrollView(
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: table, // <-- your existing table child: table, // <-- your existing table
) )
: buildMobileCardView(paginatedGroup), : buildMobileCardView(paginatedGroup),
), ),
PaginationControls( PaginationControls(
currentPage: currentPage, currentPage: currentPage,

File diff suppressed because it is too large Load Diff

View File

@ -14,12 +14,13 @@ class TaxiScreen extends StatefulWidget {
final Map<String, dynamic>? selectedItem; final Map<String, dynamic>? selectedItem;
final String? loginUser; final String? loginUser;
TaxiScreen( TaxiScreen({
{required this.onClose, required this.onClose,
this.apiData, this.apiData,
required this.onSavetaxi, required this.onSavetaxi,
required this.selectedItem, required this.selectedItem,
required this.loginUser}); required this.loginUser,
});
@override @override
_TaxiScreenState createState() => _TaxiScreenState(); _TaxiScreenState createState() => _TaxiScreenState();
@ -97,13 +98,17 @@ class _TaxiScreenState extends State<TaxiScreen> {
super.initState(); super.initState();
_addFocusListener( _addFocusListener(
_destinationFocusNode, (focus) => _destinationFocus = focus); _destinationFocusNode,
(focus) => _destinationFocus = focus,
);
_addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus); _addFocusListener(_locationFocusNode, (focus) => _locationFocus = focus);
_addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus); _addFocusListener(_dateFocusNode, (focus) => _dateFocus = focus);
_addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus); _addFocusListener(_timeFocusNode, (focus) => _timeFocus = focus);
_addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus); _addFocusListener(_taxiReqFocusNode, (focus) => _taxiReqFocused = focus);
_addFocusListener( _addFocusListener(
_numPassengerFocusNode, (focus) => _numPassengerFocus = focus); _numPassengerFocusNode,
(focus) => _numPassengerFocus = focus,
);
_addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus); _addFocusListener(_commentsFocusNode, (focus) => _commentsFocus = focus);
_destinationController = initController("destination_city"); _destinationController = initController("destination_city");
@ -168,7 +173,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
"location_of_pickup", "location_of_pickup",
"no_of_passengers", "no_of_passengers",
"date", "date",
"time" "time",
]; ];
// Check validation for each field // Check validation for each field
@ -199,30 +204,33 @@ class _TaxiScreenState extends State<TaxiScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isMobile = sizingInfo.isMobile; builder: (context, sizingInfo) {
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; bool isMobile = sizingInfo.isMobile;
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container( return Container(
// color: Color(0xFFF4F4FB), // color: Color(0xFFF4F4FB),
child: Form( child: Form(
key: _formKey, key: _formKey,
child: Padding( child: Padding(
padding: const EdgeInsets.all(16.0), padding: const EdgeInsets.all(16.0),
child: Column( child: Column(
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.all(28.0), padding: const EdgeInsets.all(28.0),
child: Center( child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)), child: Column(children: _buildAccomadtionForm(isDesktop)),
),
), ),
) ],
], ),
), ),
), ),
), );
); },
}); );
} }
List<Widget> _buildAccomadtionForm(bool isDesktop) { List<Widget> _buildAccomadtionForm(bool isDesktop) {
@ -235,7 +243,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<List<Widget>> rowBuilders = [ List<List<Widget>> rowBuilders = [
// _builClassType(isDesktop), // _builClassType(isDesktop),
_buildSecondRow(isDesktop) _buildSecondRow(isDesktop),
]; ];
return [ return [
@ -253,19 +261,24 @@ class _TaxiScreenState extends State<TaxiScreen> {
List<Widget> _buildFirstRow(isDesktop) { List<Widget> _buildFirstRow(isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? []; List<dynamic> purposeList = widget.apiData?['taxt_car_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList List<DropdownMenuItem<String>> dropdownItems =
.map((item) => DropdownMenuItem<String>( purposeList
value: item['dropdown_key'], .map(
child: Text(item['dropdown_value']), (item) => DropdownMenuItem<String>(
)) value: item['dropdown_key'],
.toList(); child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) { if (dropdownItems.isEmpty) {
dropdownItems.add( dropdownItems.add(
DropdownMenuItem<String>( DropdownMenuItem<String>(
value: null, value: null,
child: Text("No options available", child: Text(
style: TextStyle(color: Colors.grey)), "No options available",
style: TextStyle(color: Colors.grey),
),
), ),
); );
} }
@ -281,31 +294,28 @@ class _TaxiScreenState extends State<TaxiScreen> {
Text( Text(
"Taxi Required For", "Taxi Required For",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
isDesktop isDesktop
? Row(children: _buildTripType(isDesktop)) ? Row(children: _buildTripType(isDesktop))
: Column(children: _buildTripType(isDesktop)) : Column(children: _buildTripType(isDesktop)),
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Number of Passenger", "Number of Passenger",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -319,8 +329,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
keyboardType: TextInputType.numberWithOptions(decimal: true), keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.allow(RegExp( FilteringTextInputFormatter.allow(
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal RegExp(r'^\d*\.?\d*$'),
), // Allow only positive numbers with optional decimal
], ],
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Number of Passenger", labelText: "Number of Passenger",
@ -334,28 +345,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["no_of_passengers"] != null) ...[ if (errorMessages["no_of_passengers"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Car Type", "Car Type",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -369,18 +373,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding: EdgeInsets.symmetric(
EdgeInsets.symmetric(horizontal: 10), // Proper padding horizontal: 10,
), // Proper padding
), ),
onChanged: purposeList.isNotEmpty onChanged:
? (newValue) { purposeList.isNotEmpty
setState(() { ? (newValue) {
selectedCarType = newValue; setState(() {
}); selectedCarType = newValue;
print( });
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}"); print(
} "Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
: null, );
}
: null,
items: dropdownItems, items: dropdownItems,
), ),
@ -388,31 +395,31 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
], ],
), ),
if (isDesktop) if (isDesktop) SizedBox.shrink() else SizedBox(height: 8),
SizedBox.shrink()
else
SizedBox(
height: 8,
),
]; ];
} }
List<Widget> _buildTripType(bool isDesktop) { List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? []; List<dynamic> purposeList = widget.apiData?['taxi_car_required_for'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList List<DropdownMenuItem<String>> dropdownItems =
.map((item) => DropdownMenuItem<String>( purposeList
value: item['dropdown_key'], .map(
child: Text(item['dropdown_value']), (item) => DropdownMenuItem<String>(
)) value: item['dropdown_key'],
.toList(); child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) { if (dropdownItems.isEmpty) {
dropdownItems.add( dropdownItems.add(
DropdownMenuItem<String>( DropdownMenuItem<String>(
value: null, value: null,
child: Text("No options available", child: Text(
style: TextStyle(color: Colors.grey)), "No options available",
style: TextStyle(color: Colors.grey),
),
), ),
); );
} }
@ -425,9 +432,10 @@ class _TaxiScreenState extends State<TaxiScreen> {
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _taxiReqFocused, isFocused: _taxiReqFocused,
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
? MediaQuery.of(context).size.width * 0.34 isDesktop
: MediaQuery.of(context).size.width * 0.66, ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
@ -436,18 +444,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
style: TextStyle(fontSize: 12), style: TextStyle(fontSize: 12),
decoration: InputDecoration( decoration: InputDecoration(
border: InputBorder.none, border: InputBorder.none,
contentPadding: contentPadding: EdgeInsets.symmetric(
EdgeInsets.symmetric(horizontal: 10), // Proper padding horizontal: 10,
), // Proper padding
), ),
onChanged: purposeList.isNotEmpty onChanged:
? (newValue) { purposeList.isNotEmpty
setState(() { ? (newValue) {
selectedReqTaxi = newValue; setState(() {
}); selectedReqTaxi = newValue;
print( });
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}"); print(
} "Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
: null, );
}
: null,
items: dropdownItems, items: dropdownItems,
), ),
@ -466,10 +477,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
DateTime? pickedDate = await showDatePicker( DateTime? pickedDate = await showDatePicker(
context: context, context: context,
initialDate: _selectedCheckOutDate != null && initialDate:
_selectedCheckOutDate!.isAfter(today) _selectedCheckOutDate != null &&
? _selectedCheckOutDate! _selectedCheckOutDate!.isAfter(today)
: today, ? _selectedCheckOutDate!
: today,
firstDate: today, firstDate: today,
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -494,8 +506,13 @@ class _TaxiScreenState extends State<TaxiScreen> {
// Formatting time to HH:mm (24-hour format) // Formatting time to HH:mm (24-hour format)
final now = DateTime.now(); final now = DateTime.now();
final formattedTime = DateFormat('HH:mm').format( final formattedTime = DateFormat('HH:mm').format(
DateTime(now.year, now.month, now.day, pickedTime.hour, DateTime(
pickedTime.minute), now.year,
now.month,
now.day,
pickedTime.hour,
pickedTime.minute,
),
); );
_timeController.text = formattedTime; _timeController.text = formattedTime;
}); });
@ -509,9 +526,10 @@ class _TaxiScreenState extends State<TaxiScreen> {
Text( Text(
"City", "City",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -535,28 +553,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["destination_city"] != null) ...[ if (errorMessages["destination_city"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Location of Pickup", "Pickup Location",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -569,7 +580,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
controller: _locationController, controller: _locationController,
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Location of Pickup", labelText: "Pickup Location",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey), labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
@ -580,28 +591,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["location_of_pickup"] != null) ...[ if (errorMessages["location_of_pickup"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Date", "Date",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -622,8 +626,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today, suffixIcon: Icon(
size: 16, color: Colors.grey), Icons.calendar_today,
size: 16,
color: Colors.grey,
),
), ),
), ),
), ),
@ -632,28 +639,21 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["date"] != null) ...[ if (errorMessages["date"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
if (isDesktop) if (isDesktop) Spacer() else SizedBox(height: 8),
Spacer()
else
SizedBox(
height: 8,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Time", "Time",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper( CustomTextFieldItnerarySubWrapper(
@ -674,8 +674,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: suffixIcon: Icon(
Icon(Icons.access_time, size: 16, color: Colors.grey), Icons.access_time,
size: 16,
color: Colors.grey,
),
), ),
), ),
), ),
@ -684,10 +687,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
if (errorMessages["time"] != null) ...[ if (errorMessages["time"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text("Required", style: TextStyle(color: Colors.red, fontSize: 12)),
"Required",
style: TextStyle(color: Colors.red, fontSize: 12),
),
], ],
], ],
), ),
@ -702,17 +702,19 @@ class _TaxiScreenState extends State<TaxiScreen> {
Text( Text(
"Comments", "Comments",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldWrapper( CustomTextFieldWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop, isDesktop: isDesktop,
width: isDesktop width:
? MediaQuery.of(context).size.width * 0.34 isDesktop
: MediaQuery.of(context).size.width * 0.66, ? MediaQuery.of(context).size.width * 0.34
: MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
@ -733,9 +735,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
], ],
), ),
if (isDesktop) Spacer(), if (isDesktop) Spacer(),
SizedBox( SizedBox(height: 5),
height: 5,
),
Column( Column(
children: [ children: [
Row( Row(
@ -756,9 +756,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
child: Text( child: Text(
@ -767,7 +765,6 @@ class _TaxiScreenState extends State<TaxiScreen> {
), ),
), ),
SizedBox(width: 10), // Space between buttons SizedBox(width: 10), // Space between buttons
// Save Changes Button // Save Changes Button
ElevatedButton( ElevatedButton(
onPressed: () { onPressed: () {
@ -775,9 +772,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Color(0xFF114D8B), // Primary color for save backgroundColor: Color(0xFF114D8B), // Primary color for save
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
child: Text( child: Text(

View File

@ -85,7 +85,8 @@ class _FlightListWidgetState extends State<FlightListWidget> {
return AlertDialog( return AlertDialog(
title: const Text('Select Trip Type'), title: const Text('Select Trip Type'),
content: const Text( content: const Text(
'Please select a trip type before adding a flight.'), 'Please select a trip type before adding a flight.',
),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(), onPressed: () => Navigator.of(context).pop(),
@ -118,16 +119,18 @@ class _FlightListWidgetState extends State<FlightListWidget> {
// style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), // style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
// ), // ),
MouseRegion( MouseRegion(
cursor: widget.isViewMode cursor:
? SystemMouseCursors.forbidden widget.isViewMode
: SystemMouseCursors.click, ? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: GestureDetector( child: GestureDetector(
onTap: widget.isViewMode onTap:
? null widget.isViewMode
: () { ? null
checkClass(); : () {
print("New data"); checkClass();
}, print("New data");
},
child: Row( child: Row(
mainAxisSize: mainAxisSize:
MainAxisSize.min, // Ensures content fits nicely MainAxisSize.min, // Ensures content fits nicely
@ -141,7 +144,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Icons.add_circle_sharp, Icons.add_circle_sharp,
size: 30, size: 30,
color: Color(0xFF114D8B), color: Color(0xFF114D8B),
) ),
], ],
), ),
), ),
@ -149,9 +152,9 @@ class _FlightListWidgetState extends State<FlightListWidget> {
], ],
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Scroll behavior based on device
_buildData(context, isDesktop) // Scroll behavior based on device
_buildData(context, isDesktop),
], ],
), ),
), ),
@ -224,8 +227,11 @@ class _FlightListWidgetState extends State<FlightListWidget> {
if (hour == 24 && minute == 0) { if (hour == 24 && minute == 0) {
// 24:00 is treated as 00:00 on the next day // 24:00 is treated as 00:00 on the next day
dateTime = DateTime(now.year, now.month, now.day) dateTime = DateTime(
.add(const Duration(days: 1)); now.year,
now.month,
now.day,
).add(const Duration(days: 1));
} else { } else {
if (hour < 0 || hour > 23 || minute < 0 || minute > 59) { if (hour < 0 || hour > 23 || minute < 0 || minute > 59) {
throw FormatException("Invalid hour or minute"); throw FormatException("Invalid hour or minute");
@ -245,7 +251,21 @@ class _FlightListWidgetState extends State<FlightListWidget> {
itemCount: filteredList.length, itemCount: filteredList.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = filteredList[index]; final item = filteredList[index];
String? tripTypeName = '';
switch (item["trip_type"]?.toString()) {
case "Roundtrip":
tripTypeName = "Round Trip";
break;
case "Multitrip":
tripTypeName = "Multi-Trip";
break;
case "Oneway":
tripTypeName = "One-Way";
break;
default:
tripTypeName = item["trip_type"]?.toString();
break;
}
return Container( return Container(
margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6), margin: EdgeInsets.symmetric(horizontal: 8, vertical: 6),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -281,7 +301,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Row( Row(
children: [ children: [
Text( Text(
item["trip_type"]?.toString() ?? "N/A", tripTypeName ?? "N/A",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w800, fontWeight: FontWeight.w800,
@ -313,59 +333,53 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
], ],
), ),
Divider( Divider(color: Colors.blueGrey.shade50),
color: Colors.blueGrey.shade50,
),
SizedBox(height: 4), SizedBox(height: 4),
if (isDesktop) if (isDesktop)
Row( Row(
children: [ children: [
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
"Class", "Class",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 4, flex: 4,
child: Text( child: Text(
"Sector", "Sector",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
"Date", "Date",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
Expanded( Expanded(
flex: 2, flex: 2,
child: Text( child: Text(
"Time", "Time",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(fontSize: 11),
fontSize: 11, ),
), ),
)),
], ],
), ),
SizedBox(height: 4), SizedBox(height: 4),
// Trip Rows
// Trip Rows
if (isDesktop) if (isDesktop)
if (item["trips"] != null && item["trips"].isNotEmpty) if (item["trips"] != null && item["trips"].isNotEmpty)
...item["trips"].map<Widget>((trip) { ...item["trips"].map<Widget>((trip) {
String fromPlaceCountry = String fromPlaceCountry =
countryMap[trip["from_place"]?.toString()] ?? countryMap[trip["from_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
String toPlaceCountry = String toPlaceCountry =
countryMap[trip["to_place"]?.toString()] ?? countryMap[trip["to_place"]?.toString()] ??
"Unknown Country"; "Unknown Country";
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0), padding: const EdgeInsets.symmetric(vertical: 4.0),
@ -385,7 +399,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
Expanded( Expanded(
flex: 4, flex: 4,
child: Text( child: Text(
"$fromPlaceCountry (from) - (to) $toPlaceCountry", "$fromPlaceCountry (From) - (To) $toPlaceCountry",
// "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}", // "${trip["from_place"]?.toString()} - ${trip["to_place"]?.toString()}",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
@ -435,15 +449,22 @@ class _FlightListWidgetState extends State<FlightListWidget> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
_buildKeyValueRow( _buildKeyValueRow(
"Class", "Class",
getRequestForClass(trip["class"].toString()) ?? getRequestForClass(trip["class"].toString()) ??
"N/A"), "N/A",
_buildKeyValueRow("Sector", ),
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}"),
_buildKeyValueRow( _buildKeyValueRow(
"Date", formatDate(trip["date"] ?? "")), "Sector",
"${trip["from_place"] ?? "N/A"} - ${trip["to_place"] ?? "N/A"}",
),
_buildKeyValueRow( _buildKeyValueRow(
"Time", formatTime(trip["time"] ?? "")), "Date",
formatDate(trip["date"] ?? ""),
),
_buildKeyValueRow(
"Time",
formatTime(trip["time"] ?? ""),
),
], ],
), ),
), ),
@ -474,12 +495,7 @@ class _FlightListWidgetState extends State<FlightListWidget> {
), ),
), ),
Expanded( Expanded(
child: Text( child: Text(value, style: GoogleFonts.poppins(fontSize: 12)),
value,
style: GoogleFonts.poppins(
fontSize: 12,
),
),
), ),
], ],
), ),

View File

@ -131,7 +131,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"delegationEndDate", "delegationEndDate",
// "dateOfIssue", // "dateOfIssue",
// "dateOfExpiry", // "dateOfExpiry",
"changePassword" "changePassword",
]; ];
Color? layoutColor; Color? layoutColor;
@ -202,7 +202,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("API Selected User Has Data - $apiselectedUser"); print("API Selected User Has Data - $apiselectedUser");
} }
userIdApi = apiselectedUser?["user_id"] ?? ""; userIdApi = apiselectedUser?["user_id"] ?? "";
controllers["Fname"]?.text = apiselectedUser?["first_name"] ?? ""; controllers["Fname"]?.text = apiselectedUser?["first_name"] ?? "";
controllers["Lname"]?.text = apiselectedUser?["last_name"] ?? ""; controllers["Lname"]?.text = apiselectedUser?["last_name"] ?? "";
controllers["email"]?.text = apiselectedUser?["email"] ?? ""; controllers["email"]?.text = apiselectedUser?["email"] ?? "";
@ -286,7 +286,8 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
if (apiselectedUser?["delegated_to_user_id"] != null) { if (apiselectedUser?["delegated_to_user_id"] != null) {
print( print(
"UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}"); "UPDADele- ${apiselectedUser?["delegated_to_user_id"]?.toString()}",
);
selectedSubstituteApprover = selectedSubstituteApprover =
apiselectedUser?["delegated_to_user_id"]?.toString() ?? ""; apiselectedUser?["delegated_to_user_id"]?.toString() ?? "";
@ -303,12 +304,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
List<dynamic> decodedList = jsonDecode(fixedJson); List<dynamic> decodedList = jsonDecode(fixedJson);
selectedServiceIds = decodedList.map<Map<String, dynamic>>((item) { selectedServiceIds =
final map = Map<String, dynamic>.from(item); decodedList.map<Map<String, dynamic>>((item) {
return { final map = Map<String, dynamic>.from(item);
"service_id": map['service_id'].toString(), return {"service_id": map['service_id'].toString()};
}; }).toList();
}).toList();
} catch (e) { } catch (e) {
print("❌ Error decoding fixed agent_supported_service_ids: $e"); print("❌ Error decoding fixed agent_supported_service_ids: $e");
selectedServiceIds = []; selectedServiceIds = [];
@ -380,8 +380,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// userIdsApi = userMap.keys.toList(); // userIdsApi = userMap.keys.toList();
// Handle selectedUser as a Map (not a List) // Handle selectedUser as a Map (not a List)
apiselectedUser = extraData['selectedUser'] apiselectedUser =
as Map<String, dynamic>?; // Cast it as a Map extraData['selectedUser']
as Map<String, dynamic>?; // Cast it as a Map
isViewMode = extraData['isViewMode'] ?? false; isViewMode = extraData['isViewMode'] ?? false;
isEditProfile = extraData['isEditProfile'] ?? false; isEditProfile = extraData['isEditProfile'] ?? false;
}); });
@ -443,7 +444,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
userMap = { userMap = {
for (var user in userList) for (var user in userList)
user['user_id'].toString(): user['user_id'].toString():
"${user['first_name']} ${user['last_name']}" "${user['first_name']} ${user['last_name']}",
}; };
userIdsApi = userMap.keys.toList(); userIdsApi = userMap.keys.toList();
}); });
@ -481,13 +482,15 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
String? bodyStringColor = await getBodyColor(); String? bodyStringColor = await getBodyColor();
setState(() { setState(() {
layoutColor = layoutString != null layoutColor =
? Color(int.parse(layoutString)) layoutString != null
: Colors.redAccent; ? Color(int.parse(layoutString))
: Colors.redAccent;
bodyColor = bodyStringColor != null bodyColor =
? Color(int.parse(bodyStringColor)) bodyStringColor != null
: Colors.white; ? Color(int.parse(bodyStringColor))
: Colors.white;
}); });
} }
@ -538,6 +541,11 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
} }
} }
void handleGoBack() async {
print("hello, please Go Back");
printFormData();
}
void handleNext() async { void handleNext() async {
print("USR Detail Next"); print("USR Detail Next");
printFormData(); printFormData();
@ -552,35 +560,67 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("USERDETAILS : $data"); print("USERDETAILS : $data");
if (!isValidData(data)) { final tabs = {
print("USERDETAILS : $userDetials"); "personal": "Personal Details",
print("Validation Failed: Required fields are missing."); "office": "Office Details",
setState(() {}); "travel": "Travel Details",
return; // Stop execution if validation fails };
final tabKeys = tabs.keys.toList(); // ["personal", "office", "travel"]
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
print("currentIndex - $currentIndex");
bool isValid = false;
final currentTab = tabKeys[currentIndex];
if (currentTab == "personal") {
isValid = isValidData(userDetials);
} else if (currentTab == "office") {
isValid = isValidDataTwo(userDetials);
} else { } else {
print("USERDETAILS : $userDetials"); isValid = true; // Travel tab might not need validation at this point
final tabs = {
"personal": "Personal Details",
"office": "Office Details",
"travel": "Travel Details",
};
final tabKeys = tabs.keys.toList(); // ["personal", "office", "travel"]
final currentIndex = tabKeys.indexOf(selectedTab ?? "personal");
if (currentIndex < tabKeys.length - 1) {
// Move to next tab
setState(() {
selectedTab = tabKeys[currentIndex + 1];
});
} else {
// Already at last tab (travel), maybe submit form or show done message
print("All tabs completed!");
// You can trigger full form submit here
}
} }
if (!isValid) {
print("Validation Failed on $currentTab: $userDetials");
setState(() {}); // To trigger UI update showing errors
return;
}
if (currentIndex < tabKeys.length - 1) {
// Move to next tab
setState(() {
selectedTab = tabKeys[currentIndex + 1];
});
} else {
// Final step submit or show done
print("All tabs completed!");
// Submit the full form here
}
// if (!isValidData(data))
// {
// print("USERDETAILS : $userDetials");
// print("Validation Failed: Required fields are missing.");
// setState(() {});
// return; // Stop execution if validation fails
// } else
// {
// print("USERDETAILS : $userDetials");
//
// if (currentIndex < tabKeys.length - 1) {
// // Move to next tab
// setState(() {
// selectedTab = tabKeys[currentIndex + 1];
// });
// } else {
// // Already at last tab (travel), maybe submit form or show done message
// print("All tabs completed!");
// // You can trigger full form submit here
// }
// }
} }
void handleSubmit() async { void handleSubmit() async {
@ -601,7 +641,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Map<String, dynamic> data = userDetials; // Map<String, dynamic> data = userDetials;
if (!isValidData(data)) { if (!isValidData(data) && isValidDataTwo(data)) {
print("USERDETAILS : $userDetials"); print("USERDETAILS : $userDetials");
print("Validation Failed: Required fields are missing."); print("Validation Failed: Required fields are missing.");
setState(() {}); setState(() {});
@ -623,7 +663,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
"last_name", "last_name",
"email", "email",
"mobile_no", "mobile_no",
// "employeeCode" // "employeeCode",
]; ];
if (apiselectedUser == null) { if (apiselectedUser == null) {
@ -647,8 +687,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
if (data["alternate_mobile_no"] != null && if (data["alternate_mobile_no"] != null &&
data["alternate_mobile_no"].toString().isNotEmpty) { data["alternate_mobile_no"].toString().isNotEmpty) {
if (!RegExp(r"^\d{10}$") if (!RegExp(
.hasMatch(data["alternate_mobile_no"].toString())) { r"^\d{10}$",
).hasMatch(data["alternate_mobile_no"].toString())) {
errorMessages["alternate_mobile_no"] = errorMessages["alternate_mobile_no"] =
"Enter 10 digits"; // Invalid mobile number format "Enter 10 digits"; // Invalid mobile number format
} }
@ -656,14 +697,31 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Email validation // Email validation
if (data["email"] != null && data["email"].toString().isNotEmpty) { if (data["email"] != null && data["email"].toString().isNotEmpty) {
if (!RegExp(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$") if (!RegExp(
.hasMatch(data["email"].toString())) { r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
).hasMatch(data["email"].toString())) {
errorMessages["email"] = "Invalid email format"; // Invalid email format errorMessages["email"] = "Invalid email format"; // Invalid email format
} }
} }
return errorMessages.isEmpty; // Valid if there are no errors return errorMessages.isEmpty; // Valid if there are no errors
} }
bool isValidDataTwo(Map<String, dynamic> data) {
errorMessages.clear(); // Reset errors
// Required fields that must not be empty
List<String> requiredFields = ["employee_code"];
// Check validation for each field
for (String field in requiredFields) {
if (data[field] == null || data[field].toString().trim().isEmpty) {
errorMessages[field] = "Required";
}
}
return errorMessages.isEmpty; // Valid if there are no errors
}
void _clearError(String field) { void _clearError(String field) {
if (mounted && errorMessages.containsKey(field)) { if (mounted && errorMessages.containsKey(field)) {
setState(() { setState(() {
@ -814,8 +872,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print("enteredPassword - $enteredPassword "); print("enteredPassword - $enteredPassword ");
if (hashedPassword != null && hashedPassword.isNotEmpty) { if (hashedPassword != null && hashedPassword.isNotEmpty) {
bool isMatch = bool isMatch = BCrypt.checkpw(
BCrypt.checkpw(enteredPassword, hashedPassword); // Compare passwords enteredPassword,
hashedPassword,
); // Compare passwords
setState(() { setState(() {
// Ensure UI updates // Ensure UI updates
@ -825,8 +885,9 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
print(" Password match!"); print(" Password match!");
} else { } else {
print(" Password NOT match!"); print(" Password NOT match!");
errorMessages errorMessages.remove(
.remove("password"); // Clear error if password is different "password",
); // Clear error if password is different
} }
}); });
} else { } else {
@ -836,32 +897,36 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) { return ResponsiveBuilder(
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop; builder: (context, sizingInfo) {
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Scaffold( return Scaffold(
backgroundColor: Color(0xFFf5f5f5), backgroundColor: Color(0xFFf5f5f5),
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '), // appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false), // drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
appBar: CustomAppBar(isDesktop: isDesktop), appBar: CustomAppBar(isDesktop: isDesktop),
drawer: CustomDrawer(isDesktop: false), drawer: CustomDrawer(isDesktop: false),
body: Padding( body: Padding(
padding: isDesktop padding:
? EdgeInsets.symmetric( isDesktop
horizontal: MediaQuery.of(context).size.width * ? EdgeInsets.symmetric(
0.1, // 30% of screen width as horizontal padding horizontal:
vertical: MediaQuery.of(context).size.height * MediaQuery.of(context).size.width *
0, // 5% of screen height as vertical padding 0.1, // 30% of screen width as horizontal padding
) vertical:
: EdgeInsets.all(0), MediaQuery.of(context).size.height *
child: Row( 0, // 5% of screen height as vertical padding
children: [ )
Expanded(child: buildData(isDesktop, context)), : EdgeInsets.all(0),
], child: Row(
children: [Expanded(child: buildData(isDesktop, context))],
),
), ),
), );
); },
}); );
} }
Widget buildData(bool isDesktop, context) { Widget buildData(bool isDesktop, context) {
@ -875,9 +940,10 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
children: [ children: [
Expanded( Expanded(
child: Container( child: Container(
height: isDesktop height:
? MediaQuery.of(context).size.height * 0.98 isDesktop
: MediaQuery.of(context).size.height, ? MediaQuery.of(context).size.height * 0.98
: MediaQuery.of(context).size.height,
child: Padding( child: Padding(
padding: EdgeInsets.all(0.0), padding: EdgeInsets.all(0.0),
child: _buildUserDetails(isDesktop), child: _buildUserDetails(isDesktop),
@ -887,25 +953,32 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Container( Container(
color: Colors.white, color: Colors.white,
child: Padding( child: Padding(
padding: const EdgeInsets.all(8.0), padding: const EdgeInsets.all(8.0),
child: isDesktop child:
? Row( isDesktop
? Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: (selectedTab == "travel" || children:
selectedRole == "5" || (selectedTab == "travel" ||
setSelectesUserType == true) selectedRole == "5" ||
? _buildSubmit(isDesktop, layoutColor!) setSelectesUserType == true)
: _buildNext(isDesktop, layoutColor!), ? _buildSubmit(isDesktop, layoutColor!)
: _buildNext(
isDesktop,
layoutColor!,
), // _buildGoBack(isDesktop, layoutColor!),
) )
: Row( : Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end,
children: (selectedTab == "travel" || children:
selectedRole == "5" || (selectedTab == "travel" ||
setSelectesUserType == true) selectedRole == "5" ||
? _buildSubmit(isDesktop, layoutColor!) setSelectesUserType == true)
: _buildNext(isDesktop, layoutColor!), ? _buildSubmit(isDesktop, layoutColor!)
)), : _buildNext(isDesktop, layoutColor!),
) ),
),
),
], ],
), ),
); );
@ -944,25 +1017,22 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// }) // })
], ],
), ),
SizedBox( SizedBox(height: 18),
height: 18,
),
isDesktop isDesktop
? buildTabsForUser() ? buildTabsForUser()
: SingleChildScrollView( : SingleChildScrollView(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: buildTabsForUser(), child: buildTabsForUser(),
), ),
Container( Container(
// color: Colors.yellow.shade50, // color: Colors.yellow.shade50,
height: MediaQuery.of(context).size.height * 0.64, height: MediaQuery.of(context).size.height * 0.64,
child: Row( child: Row(
children: [ children: [
Expanded(child: buildTabContents(isDesktop, isViewMode)), Expanded(child: buildTabContents(isDesktop, isViewMode)),
], ],
), ),
) ),
], ],
), ),
), ),
@ -977,7 +1047,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
personalDetailsKey: personalDetailsKey, personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode, isViewMode: isViewMode,
userIdApi:userIdApi, userIdApi: userIdApi,
controllers: controllers, controllers: controllers,
errorMessages: errorMessages, errorMessages: errorMessages,
selectedGender: selectedGender, selectedGender: selectedGender,
@ -1012,7 +1082,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return OfficeDetails( return OfficeDetails(
isDesktop: isDesktop, // pass isDesktop as a named argument isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode, isViewMode: isViewMode,
userIdApi:userIdApi, userIdApi: userIdApi,
controllers: controllers, controllers: controllers,
errorMessages: errorMessages, errorMessages: errorMessages,
selectedLevel: selectedLevel, selectedLevel: selectedLevel,
@ -1063,14 +1133,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
errorMessages: errorMessages, errorMessages: errorMessages,
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
passportFileUrlFromApi: passportFileUrlFromApi, passportFileUrlFromApi: passportFileUrlFromApi,
userIdApi:userIdApi, userIdApi: userIdApi,
); );
default: default:
return PersonalDetails( return PersonalDetails(
personalDetailsKey: personalDetailsKey, personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode, isViewMode: isViewMode,
userIdApi:userIdApi, userIdApi: userIdApi,
controllers: controllers, controllers: controllers,
errorMessages: errorMessages, errorMessages: errorMessages,
selectedGender: selectedGender, selectedGender: selectedGender,
@ -1101,9 +1171,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
Map<String, String> getTabs(bool setSelectesUserType) { Map<String, String> getTabs(bool setSelectesUserType) {
if (setSelectesUserType || selectedRole == "5") { if (setSelectesUserType || selectedRole == "5") {
return { return {"personal": "Personal Details"};
"personal": "Personal Details",
};
} else { } else {
return allTabs; return allTabs;
} }
@ -1113,50 +1181,102 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.end, // important crossAxisAlignment: CrossAxisAlignment.end, // important
children: tabs.entries.map((entry) { children:
final isSelected = selectedTab == entry.key; tabs.entries.map((entry) {
return GestureDetector( final isSelected = selectedTab == entry.key;
onTap: () { return GestureDetector(
setState(() { onTap: () {
selectedTab = entry.key; setState(() {
}); bool isValid = false;
},
child: Padding( final currentTab = selectedTab;
padding: const EdgeInsets.only(right: 24.0), // space between tabs if (currentTab == "personal") {
child: Column( isValid = isValidData(userDetials);
mainAxisSize: MainAxisSize.min,
children: [ if (isValid) {
Text( selectedTab = entry.key;
entry.value, }
style: GoogleFonts.poppins( } else if (currentTab == "office") {
fontSize: 12, isValid = isValidDataTwo(userDetials);
fontWeight: FontWeight.w600, if (isValid) {
color: isSelected ? Color(0xFF114D8B) : Color(0xFF475569), selectedTab = entry.key;
), }
} else {
isValid =
true; // Travel tab might not need validation at this point
selectedTab = entry.key;
}
});
},
child: Padding(
padding: const EdgeInsets.only(
right: 24.0,
), // space between tabs
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
entry.value,
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color:
isSelected ? Color(0xFF114D8B) : Color(0xFF475569),
),
),
const SizedBox(height: 8),
AnimatedContainer(
duration: Duration(milliseconds: 300),
height: 2,
width: isSelected ? 50 : 0, // small line
color: Color(0xFF114D8B),
),
],
), ),
const SizedBox(height: 8), ),
AnimatedContainer( );
duration: Duration(milliseconds: 300), }).toList(),
height: 2,
width: isSelected ? 50 : 0, // small line
color: Color(0xFF114D8B),
),
],
),
),
);
}).toList(),
); );
} }
// ---- Submit --------------------------------------- // ---- Submit ---------------------------------------
List<Widget> _buildGoBack(isDesktop, Color layoutColor) {
return [
MouseRegion(
cursor:
isViewMode
? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor:
isViewMode ? Colors.white : Colors.white, // Keep original color
disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: handleGoBack,
child: Text("Back"),
),
),
];
}
List<Widget> _buildNext(isDesktop, Color layoutColor) { List<Widget> _buildNext(isDesktop, Color layoutColor) {
return [ return [
MouseRegion( MouseRegion(
cursor: isViewMode cursor:
? SystemMouseCursors.forbidden isViewMode
: SystemMouseCursors.click, ? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor:
@ -1177,41 +1297,42 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// isViewMode ? null : handleNext, // Disable when in view mode // isViewMode ? null : handleNext, // Disable when in view mode
child: Text("Next"), child: Text("Next"),
), ),
) ),
]; ];
} }
List<Widget> _buildSubmit(isDesktop, Color layoutColor) { List<Widget> _buildSubmit(isDesktop, Color layoutColor) {
return [ return [
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: Colors.white,
foregroundColor: layoutColor, foregroundColor: layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: BorderSide(color: layoutColor, width: 2), side: BorderSide(color: layoutColor, width: 2),
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
onPressed: () { padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
isEditProfile ? context.go('/listPlan') : context.go('/listUser'); ),
}, onPressed: () {
child: Text("Cancel")), isEditProfile ? context.go('/listPlan') : context.go('/listUser');
SizedBox( },
width: 20, child: Text("Cancel"),
), ),
SizedBox(width: 20),
if (!isViewMode) if (!isViewMode)
MouseRegion( MouseRegion(
cursor: isViewMode cursor:
? SystemMouseCursors.forbidden isViewMode
: SystemMouseCursors.click, ? SystemMouseCursors.forbidden
: SystemMouseCursors.click,
child: ElevatedButton( child: ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: backgroundColor:
isViewMode ? layoutColor : layoutColor, // Keep original color isViewMode ? layoutColor : layoutColor, // Keep original color
foregroundColor: isViewMode foregroundColor:
? Colors.white isViewMode
: Colors.white, // Keep original color ? Colors.white
: Colors.white, // Keep original color
disabledBackgroundColor: disabledBackgroundColor:
layoutColor, // Ensure color remains when disabled layoutColor, // Ensure color remains when disabled
disabledForegroundColor: Colors.white, disabledForegroundColor: Colors.white,
@ -1225,7 +1346,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
isViewMode ? null : handleSubmit, // Disable when in view mode isViewMode ? null : handleSubmit, // Disable when in view mode
child: Text("Submit"), child: Text("Submit"),
), ),
) ),
]; ];
} }
} }

View File

@ -17,7 +17,6 @@ class OfficeDetails extends StatefulWidget {
final bool isViewMode; final bool isViewMode;
final String? userIdApi; final String? userIdApi;
final ValueChanged<String?>? onLevelChanged; final ValueChanged<String?>? onLevelChanged;
final ValueChanged<String?>? onDepartmentChanged; final ValueChanged<String?>? onDepartmentChanged;
final ValueChanged<String?>? onFirstApproverChanged; final ValueChanged<String?>? onFirstApproverChanged;
@ -157,17 +156,25 @@ class _OfficeDetailsState extends State<OfficeDetails> {
fetchFindGroup(); fetchFindGroup();
} }
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async { Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
try { try {
// Basic validation: Check mobile number length
if (field == "employeeCode") { final response = await apiService.CheckDuplicate(
field = "employee_code"; label,
} field,
value,
final response = await apiService.CheckDuplicate(label, field, value, userId); userId,
);
if (response.isNotEmpty) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -290,7 +297,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 10), SizedBox(height: 20),
_buildFirstRow(widget.isDesktop), _buildFirstRow(widget.isDesktop),
if (widget.isDesktop) SizedBox(height: 10), if (widget.isDesktop) SizedBox(height: 10),
_buildSecondRow(widget.isDesktop), _buildSecondRow(widget.isDesktop),
@ -407,7 +414,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Employee Code", "Employee Code *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -425,8 +432,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
controller: widget.controllers["employeeCode"], controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("employeeCode"); _clearError("employee_code");
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi); apiCheckDuplicate(
"Employee Code",
"employee_code",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Employee Code", labelText: "Employee Code",
@ -441,10 +453,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
), ),
), ),
), ),
if (widget.errorMessages["employeeCode"] != null) ...[ if (widget.errorMessages["employee_code"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
Text( Text(
widget.errorMessages["employeeCode"]!, widget.errorMessages["employee_code"]!,
style: TextStyle(color: Colors.red, fontSize: 12), style: TextStyle(color: Colors.red, fontSize: 12),
), ),
], ],
@ -452,7 +464,71 @@ class _OfficeDetailsState extends State<OfficeDetails> {
); );
} }
// Widget buildDepartmentFieldOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Department",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// isFocused: false, // Dropdown doesn't use focus
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 45, // Set appropriate height
// child: DropdownButtonFormField<String>(
// value: selectedDepartment,
// // value: widget.isViewMode ? null : selectedDepartment,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// widget.isViewMode
// ? null
// : (newValue) {
// setState(() {
// selectedDepartment = newValue;
// });
// widget.onDepartmentChanged?.call(newValue);
// },
//
// items:
// apiCostData?.map<DropdownMenuItem<String>>((item) {
// return DropdownMenuItem(
//
// value: item['department_id'], // ID as value
// child: Text(item['name'] ?? "Unknown"),
// );
// }).toList(),
// hint: Text("Select"),
// disabledHint: Text(
// selectedDepartment ?? "Select Department",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
// ),
// ),
// ],
// );
// }
Widget buildDepartmentField() { Widget buildDepartmentField() {
// Map department_id to department_name
Map<String, String> departmentMap = {
for (var item in apiCostData ?? [])
item['department_id'] as String: item['name'] as String,
};
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -466,41 +542,74 @@ class _OfficeDetailsState extends State<OfficeDetails> {
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus isFocused: false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 45, // Set appropriate height height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
value: selectedDepartment, selectedItem: departmentMap[selectedDepartment],
// value: widget.isViewMode ? null : selectedDepartment, enabled: !widget.isViewMode,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), popupProps: PopupProps.menu(
decoration: InputDecoration( showSearchBox: true,
border: InputBorder.none, fit: FlexFit.loose,
contentPadding: EdgeInsets.symmetric( menuProps: const MenuProps(backgroundColor: Colors.white),
horizontal: 10, itemBuilder:
), // Proper padding (context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 200),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Department...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
), ),
items: departmentMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Department",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
: (newValue) { : (String? newValue) {
if (newValue == null) return;
final departmentId =
departmentMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() { setState(() {
selectedDepartment = newValue; selectedDepartment = departmentId;
}); });
widget.onDepartmentChanged?.call(newValue);
widget.onDepartmentChanged?.call(
departmentId,
); // Send department_id
}, },
items:
apiCostData?.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem(
value: item['department_id'], // ID as value
child: Text(item['name'] ?? "Unknown"),
);
}).toList(),
hint: Text("Select"),
disabledHint: Text(
selectedDepartment ?? "Select Department",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
), ),
), ),
), ),
@ -585,6 +694,17 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height fit: FlexFit.loose, // Allows flexible height
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
constraints: BoxConstraints(maxHeight: 250), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -686,6 +806,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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: 250), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -806,6 +942,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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: 250), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -925,6 +1077,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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: 250), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -1047,6 +1215,22 @@ class _OfficeDetailsState extends State<OfficeDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, showSearchBox: true,
fit: FlexFit.loose, // Allows flexible height 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: 250), constraints: BoxConstraints(maxHeight: 250),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(

View File

@ -157,7 +157,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
}); });
} }
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async { Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
try { try {
// Basic validation: Check mobile number length // Basic validation: Check mobile number length
if (field == "mobile_no" && value.length != 10) { if (field == "mobile_no" && value.length != 10) {
@ -167,10 +172,16 @@ class PersonalDetailsState extends State<PersonalDetails> {
return; // Skip the API call if input is invalid return; // Skip the API call if input is invalid
} }
final response = await apiService.CheckDuplicate(label, field, value, userId); final response = await apiService.CheckDuplicate(
label,
field,
value,
userId,
);
if (response.isNotEmpty) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label Already Exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -182,9 +193,6 @@ class PersonalDetailsState extends State<PersonalDetails> {
} }
} }
void _clearError(String field) { void _clearError(String field) {
setState(() { setState(() {
widget.errorMessages.remove(field); widget.errorMessages.remove(field);
@ -305,11 +313,11 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
SizedBox(height: 10), SizedBox(height: 20),
_buildFirstRow(widget.isDesktop), _buildFirstRow(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
_buildSecondRow(widget.isDesktop), _buildSecondRow(widget.isDesktop),
// SizedBox(height: 10), SizedBox(height: 10),
_buildThirdRow(widget.isDesktop), _buildThirdRow(widget.isDesktop),
SizedBox(height: 10), SizedBox(height: 10),
_buildForthRow(widget.isDesktop), _buildForthRow(widget.isDesktop),
@ -731,7 +739,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"First Name", "First Name *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -781,7 +789,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Last Name", "Last Name*",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -822,7 +830,107 @@ class PersonalDetailsState extends State<PersonalDetails> {
); );
} }
// Widget buildGenderFieldOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Gender",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// width:
// widget.isDesktop
// ? MediaQuery.of(context).size.width * 0.12
// : null,
// isFocused: false,
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 40,
// child: DropdownButtonFormField<String>(
// // value: selectedGender,
// value: widget.isViewMode ? null : selectedGender,
// onChanged:
// widget.isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// selectedGender = newValue;
// print("selectedGender - $selectedGender");
// });
//
// widget.onGenderChanged?.call(newValue);
// },
// decoration: InputDecoration(
// border: InputBorder.none,
// enabled: !widget.isViewMode, // Disables input when in view mode
// ),
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// items: [
// DropdownMenuItem(value: "Male", child: Text("Male")),
// DropdownMenuItem(value: "Female", child: Text("Female")),
// ],
// hint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// disabledHint: Text(
// selectedGender ?? "Select Gender",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
//
// // child: DropdownSearch<String>(
// // selectedItem: selectedGender,
// // // key: ValueKey(selectedGender),
// // popupProps: PopupProps.menu(
// // fit: FlexFit.loose, // Allows flexible height
// // constraints: BoxConstraints(maxHeight: 250),
// //
// // ),
// // items: ["Male", "Female", "Others"],
// // 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",
// // style: TextStyle(fontSize: 12),
// // ),
// // ),
// // onChanged: isViewMode
// // ? null
// // : (String? newValue) {
// // setState(() {
// // // Find the country_code based on selected country_name
// // selectedGender = newValue;
// // print("selectedGender - $selectedGender");
// // // if (selectedCountry!.isNotEmpty) {
// // // errorMessages.remove("country_code");
// // // }
// // });
// // },
// //
// //
// // ),
// ),
// ),
// ],
// );
// }
Widget buildGenderField() { Widget buildGenderField() {
List<String> genderOptions = ["Male", "Female"];
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -844,9 +952,45 @@ class PersonalDetailsState extends State<PersonalDetails> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
// value: selectedGender, selectedItem: selectedGender,
value: widget.isViewMode ? null : 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(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
),
items: genderOptions,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
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,
),
),
),
onChanged: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
@ -855,65 +999,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
selectedGender = newValue; selectedGender = newValue;
print("selectedGender - $selectedGender"); print("selectedGender - $selectedGender");
}); });
widget.onGenderChanged?.call(newValue); widget.onGenderChanged?.call(newValue);
}, },
decoration: InputDecoration(
border: InputBorder.none,
enabled: !widget.isViewMode, // Disables input when in view mode
),
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
items: [
DropdownMenuItem(value: "Male", child: Text("Male")),
DropdownMenuItem(value: "Female", child: Text("Female")),
],
hint: Text(
selectedGender ?? "Select Gender",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
disabledHint: Text(
selectedGender ?? "Select Gender",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
), ),
// child: DropdownSearch<String>(
// selectedItem: selectedGender,
// // key: ValueKey(selectedGender),
// popupProps: PopupProps.menu(
// fit: FlexFit.loose, // Allows flexible height
// constraints: BoxConstraints(maxHeight: 250),
//
// ),
// items: ["Male", "Female", "Others"],
// 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",
// style: TextStyle(fontSize: 12),
// ),
// ),
// onChanged: isViewMode
// ? null
// : (String? newValue) {
// setState(() {
// // Find the country_code based on selected country_name
// selectedGender = newValue;
// print("selectedGender - $selectedGender");
// // if (selectedCountry!.isNotEmpty) {
// // errorMessages.remove("country_code");
// // }
// });
// },
//
//
// ),
), ),
), ),
], ],
@ -1014,7 +1102,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Email", "Email *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1032,7 +1120,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
controller: widget.controllers["email"], controller: widget.controllers["email"],
onChanged: (value) { onChanged: (value) {
_clearError("email"); _clearError("email");
apiCheckDuplicate("Email", "email",value,widget.userIdApi); apiCheckDuplicate("Email", "email", value, widget.userIdApi);
}, },
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
decoration: InputDecoration( decoration: InputDecoration(
@ -1064,7 +1152,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Mobile Number", "Mobile Number *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1083,7 +1171,12 @@ class PersonalDetailsState extends State<PersonalDetails> {
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("mobile_no"); _clearError("mobile_no");
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi); apiCheckDuplicate(
"Mobile Number",
"mobile_no",
value,
widget.userIdApi,
);
}, },
keyboardType: TextInputType.numberWithOptions(decimal: true), keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [ inputFormatters: [
@ -1208,6 +1301,18 @@ class PersonalDetailsState extends State<PersonalDetails> {
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality showSearchBox: true, // Enables search functionality
fit: FlexFit.loose, // Allows flexible height 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: 200), constraints: BoxConstraints(maxHeight: 200),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
@ -1323,12 +1428,79 @@ class PersonalDetailsState extends State<PersonalDetails> {
); );
} }
// Widget buildRoleOld() {
// return Column(
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Text(
// "Role ",
// style: GoogleFonts.poppins(
// fontSize: 12,
// fontWeight: FontWeight.w600,
// color: Color(0xFF575A74),
// ),
// ),
// SizedBox(height: 5),
// CustomTextFieldUserWrapper(
// isFocused: false, // Dropdown doesn't use focus
// isDesktop: widget.isDesktop,
// child: SizedBox(
// height: 45, // Set appropriate height
// child: DropdownButtonFormField<String>(
// // value: widget.isViewMode ? null : selectedRole,
// value: selectedRole,
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding: EdgeInsets.symmetric(
// horizontal: 10,
// ), // Proper padding
// ),
// onChanged:
// widget.isViewMode
// ? null
// : (newValue) {
// setState(() {
// selectedRole = newValue;
// isTravelAgent = selectedRole == "5";
// // Pass the result back to parent
// widget.onUserTypeChanged?.call(isTravelAgent);
// });
// widget.onRoleChanged?.call(newValue);
// },
// items:
// apiRoleData?.map<DropdownMenuItem<String>>((item) {
// return DropdownMenuItem(
// value: item['dropdown_key'], // ID as value
// child: Text(item['dropdown_value'] ?? "Select Role"),
// );
// }).toList(),
// hint: Text("Select Role"),
// disabledHint: Text(
// selectedRole ?? "Select Role",
// style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
// ),
// ),
// ),
// ),
// ],
// );
// }
Widget buildRole() { Widget buildRole() {
// Map dropdown_key (ID) -> dropdown_value (Name)
Map<String, String> roleMap = {
for (var item in apiRoleData ?? [])
item['dropdown_key'] as String: item['dropdown_value'] as String,
};
List<String> roleNames = roleMap.values.toList();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Role ", "Role",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@ -1337,44 +1509,73 @@ class PersonalDetailsState extends State<PersonalDetails> {
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
isFocused: false, // Dropdown doesn't use focus isFocused: false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 45, // Set appropriate height height: 40,
child: DropdownButtonFormField<String>( child: DropdownSearch<String>(
// value: widget.isViewMode ? null : selectedRole, selectedItem: selectedRole != null ? roleMap[selectedRole] : null,
value: selectedRole, enabled: !widget.isViewMode,
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black), popupProps: PopupProps.menu(
decoration: InputDecoration( showSearchBox: true,
border: InputBorder.none, fit: FlexFit.loose,
contentPadding: EdgeInsets.symmetric( constraints: BoxConstraints(maxHeight: 250),
horizontal: 10, menuProps: const MenuProps(backgroundColor: Colors.white),
), // Proper padding 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),
),
),
), ),
items: roleNames,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Role",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: onChanged:
widget.isViewMode widget.isViewMode
? null ? null
: (newValue) { : (String? newValue) {
if (newValue == null) return;
final selectedKey =
roleMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() { setState(() {
selectedRole = newValue; selectedRole = selectedKey;
isTravelAgent = selectedRole == "5"; isTravelAgent = selectedKey == "5";
// Pass the result back to parent
widget.onUserTypeChanged?.call(isTravelAgent);
}); });
widget.onRoleChanged?.call(newValue);
widget.onUserTypeChanged?.call(isTravelAgent);
widget.onRoleChanged?.call(selectedKey);
}, },
items:
apiRoleData?.map<DropdownMenuItem<String>>((item) {
return DropdownMenuItem(
value: item['dropdown_key'], // ID as value
child: Text(item['dropdown_value'] ?? "Select Role"),
);
}).toList(),
hint: Text("Select Role"),
disabledHint: Text(
selectedRole ?? "Select Role",
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
),
), ),
), ),
), ),
@ -1429,7 +1630,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Password", "Password *",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,

View File

@ -33,7 +33,6 @@ class TravellerDetails extends StatefulWidget {
final String? passportFileUrlFromApi; final String? passportFileUrlFromApi;
final String? userIdApi; final String? userIdApi;
const TravellerDetails({ const TravellerDetails({
Key? key, Key? key,
required this.controllers, required this.controllers,
@ -149,15 +148,24 @@ class TravellerDetailsState extends State<TravellerDetails> {
}); });
} }
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async { Future<void> apiCheckDuplicate(
String label,
String field,
String value,
String? userId,
) async {
var newField = "";
try { try {
if(field == "forex_card_num"){ final response = await apiService.CheckDuplicate(
field = "forex_pre_paid_card_number"; label,
} newField,
final response = await apiService.CheckDuplicate(label, field, value, userId); value,
userId,
);
if (response.isNotEmpty) { if (response.isNotEmpty) {
_clearError(field); _clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists"; widget.errorMessages[field] =
response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}"); print("Duplicate found: ${response['message']}");
return; return;
} else { } else {
@ -705,6 +713,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: MediaQuery.of(context).size.height, height: MediaQuery.of(context).size.height,
padding: const EdgeInsets.only(top: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(
top: BorderSide( top: BorderSide(
@ -1107,7 +1116,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["passportNumber"], controller: controllers["passportNumber"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("last_name"); _clearError("passport_number");
apiCheckDuplicate(
"Passport Number",
"passport_number",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Passport Number", labelText: "Passport Number",
@ -1122,6 +1137,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
), ),
), ),
), ),
if (widget.errorMessages["passport_number"] != null) ...[
SizedBox(height: 5), // Space before error message
Text(
widget.errorMessages["passport_number"]!,
style: TextStyle(color: Colors.red, fontSize: 12),
),
],
], ],
); );
} }
@ -1181,7 +1203,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
_selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today) _selectedDateOfIssue != null && _selectedDateOfIssue!.isAfter(today)
? _selectedDateOfIssue! ? _selectedDateOfIssue!
: today, : today,
firstDate: today, // firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -1271,7 +1294,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
_selectedDateOfExpiry!.isAfter(today) _selectedDateOfExpiry!.isAfter(today)
? _selectedDateOfExpiry! ? _selectedDateOfExpiry!
: today, : today,
firstDate: today, // firstDate: today,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -2330,8 +2354,13 @@ class TravellerDetailsState extends State<TravellerDetails> {
controller: controllers["forex_card_num"], controller: controllers["forex_card_num"],
enabled: !widget.isViewMode, enabled: !widget.isViewMode,
onChanged: (value) { onChanged: (value) {
_clearError("forex_card_num"); _clearError("forex_pre_paid_card_number");
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi); apiCheckDuplicate(
"Forex Pre-Paid Card Number",
"forex_pre_paid_card_number",
value,
widget.userIdApi,
);
}, },
decoration: InputDecoration( decoration: InputDecoration(
labelText: "Card Number", labelText: "Card Number",
@ -2467,9 +2496,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60, height: 60,
child: Center( child: Center(
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here padding: EdgeInsets.only(
top: 20,
left: 8,
), // 👈 Add top padding here
child: IconButton( child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -2480,7 +2516,6 @@ class TravellerDetailsState extends State<TravellerDetails> {
), ),
), ),
), ),
], ],
) )
: Column( : Column(
@ -2491,7 +2526,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildFrequentFlierInformation(entry), buildFrequentFlierInformation(entry),
SizedBox(width: 15), SizedBox(width: 15),
IconButton( IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -2773,30 +2812,37 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: child:
widget.isDesktop widget.isDesktop
? Row( ? Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
buildHotel(entry), buildHotel(entry),
SizedBox(width: 25), SizedBox(width: 25),
buildHotelMembershipNum(entry), buildHotelMembershipNum(entry),
SizedBox( SizedBox(
height: 60, height: 60,
child: Center( child: Center(
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here padding: EdgeInsets.only(
child: IconButton( top: 20,
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), left: 8,
tooltip: 'Cancel the Details', ), // 👈 Add top padding here
onPressed: () { child: IconButton(
setState(() { icon: Icon(
removeHotelLoyaltyEntry(entry); Icons.remove_circle_sharp,
}); color: Colors.red,
}, size: 15,
),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
removeHotelLoyaltyEntry(entry);
});
},
),
),
), ),
), ),
), ],
), )
],
)
: Column( : Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@ -2804,7 +2850,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8), SizedBox(height: 8),
buildHotelMembershipNum(entry), buildHotelMembershipNum(entry),
IconButton( IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -3035,9 +3085,16 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 60, height: 60,
child: Center( child: Center(
child: Padding( child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here padding: EdgeInsets.only(
top: 20,
left: 8,
), // 👈 Add top padding here
child: IconButton( child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -3061,7 +3118,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8), SizedBox(height: 8),
buildVisaValidUpTo(entry), buildVisaValidUpTo(entry),
IconButton( IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15), icon: Icon(
Icons.remove_circle_sharp,
color: Colors.red,
size: 15,
),
tooltip: 'Cancel the Details', tooltip: 'Cancel the Details',
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -3187,6 +3248,116 @@ class TravellerDetailsState extends State<TravellerDetails> {
); );
} }
List<dynamic> purposeList = apiData?['visa_type_of_visa'];
// Map for id => name
Map<String, String> visaTypeMap = {
for (var item in purposeList)
item['dropdown_key'].toString(): item['dropdown_value'].toString(),
};
// Selected value from entry
String? selectedPurpose = entry['visa_type_id']?.toString();
if (!visaTypeMap.containsKey(selectedPurpose)) {
selectedPurpose = null;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Visa Type",
style: GoogleFonts.poppins(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldUserTravellerWrapper(
width:
widget.isDesktop
? MediaQuery.of(context).size.width * 0.17
: null,
isFocused: false,
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: DropdownSearch<String>(
selectedItem: visaTypeMap[selectedPurpose],
enabled: purposeList.isNotEmpty,
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
constraints: BoxConstraints(maxHeight: 200),
itemBuilder:
(context, item, isSelected) => Container(
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Text(
item,
style: GoogleFonts.poppins(fontSize: 11.5),
),
),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search Visa Type...",
hintStyle: GoogleFonts.poppins(fontSize: 11.5),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: visaTypeMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(horizontal: 1),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select Visa Type",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: (newValue) {
if (newValue == null) return;
final selectedId =
visaTypeMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
setState(() {
entry['visa_type_id'] = selectedId;
});
print("Updating form data: visa_type_id -> $selectedId");
},
),
),
),
],
);
}
Widget buildVisaType3(entry) {
if (apiData == null || apiData?['visa_type_of_visa'] == null) {
return Center(
child: Transform.scale(scale: 0.5, child: CircularProgressIndicator()),
);
}
// List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? []; // List<dynamic> purposeList = apiData?['visa_type_of_visa'] ?? [];
// List<dynamic> purposeList = []; // List<dynamic> purposeList = [];
List<dynamic> purposeList = apiData?['visa_type_of_visa']; List<dynamic> purposeList = apiData?['visa_type_of_visa'];
@ -3402,8 +3573,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker( final pickedDate = await showDatePicker(
context: context, context: context,
initialDate: initialDate, // initialDate: initialDate,
firstDate: initialDate, // firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );
@ -3490,8 +3662,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
final pickedDate = await showDatePicker( final pickedDate = await showDatePicker(
context: context, context: context,
initialDate: initialDate, // initialDate: initialDate,
firstDate: initialDate, // firstDate: initialDate,
firstDate: DateTime(1900),
lastDate: DateTime(2100), lastDate: DateTime(2100),
); );

View File

@ -2,7 +2,7 @@ import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'dart:html' as html; import 'dart:html' as html;
import 'package:frontend/config/apiUrl.dart'; // 1 newly added import 'package:frontend/config/apiUrl.dart'; // 1 newly added
import 'package:frontend/services/apiService.dart'; import 'package:frontend/services/apiService.dart';
@ -31,7 +31,7 @@ class _MyAppState extends State<MyApp> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
// SemanticsBinding.instance.ensureSemantics(); // Safe here SemanticsBinding.instance.ensureSemantics(); // Safe here
if (kIsWeb) { if (kIsWeb) {
final uri = Uri.parse(html.window.location.href); final uri = Uri.parse(html.window.location.href);
if (uri.path == '/authredirection' && if (uri.path == '/authredirection' &&

View File

@ -1,3 +1,3 @@
//api url //api url
const String apiUrl = 'http://apitest.tripapprovaltool.com'; const String apiUrl = 'http://apitest.tripapprovaltool.com/tstat_be';
// const String apiUrl = 'https://uat.tripapprovaltool.com'; // const String apiUrl = 'https://uat.tripapprovaltool.com';