issues fixes

This commit is contained in:
venba-Inspriron-3558 2025-06-03 18:08:43 +05:30
parent 1005ff962d
commit 5d7faf309a
5 changed files with 193 additions and 32 deletions

View File

@ -1012,6 +1012,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
return OfficeDetails(
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
userIdApi:userIdApi,
controllers: controllers,
errorMessages: errorMessages,
selectedLevel: selectedLevel,
@ -1062,12 +1063,14 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
errorMessages: errorMessages,
travelDetails: travelDetailsDataFromAPI, // 👈 Pass this down
passportFileUrlFromApi: passportFileUrlFromApi,
userIdApi:userIdApi,
);
default:
return PersonalDetails(
personalDetailsKey: personalDetailsKey,
isDesktop: isDesktop, // pass isDesktop as a named argument
isViewMode: isViewMode,
userIdApi:userIdApi,
controllers: controllers,
errorMessages: errorMessages,
selectedGender: selectedGender,

View File

@ -15,6 +15,8 @@ class OfficeDetails extends StatefulWidget {
final Map<String, String> errorMessages;
final bool isDesktop;
final bool isViewMode;
final String? userIdApi;
final ValueChanged<String?>? onLevelChanged;
final ValueChanged<String?>? onDepartmentChanged;
@ -48,6 +50,7 @@ class OfficeDetails extends StatefulWidget {
this.onThirdApproverChanged,
this.selectedSubstituteApprover,
this.onFirstSubsApproverChanged,
this.userIdApi,
}) : super(key: key);
@override
@ -154,6 +157,28 @@ class _OfficeDetailsState extends State<OfficeDetails> {
fetchFindGroup();
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
try {
if (field == "employeeCode") {
field = "employee_code";
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}");
return;
} else {
_clearError(field);
print("No duplicates found.");
}
} catch (e) {
print("Error in checkDuplicate: $e");
}
}
void _clearError(String field) {
setState(() {
widget.errorMessages.remove(field);
@ -412,6 +437,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("employeeCode");
apiCheckDuplicate("Employee Code", "employeeCode",value,widget.userIdApi);
},
decoration: InputDecoration(
labelText: "Employee Code",

View File

@ -157,6 +157,34 @@ class PersonalDetailsState extends State<PersonalDetails> {
});
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
try {
// Basic validation: Check mobile number length
if (field == "mobile_no" && value.length != 10) {
_clearError(field);
widget.errorMessages[field] = "$label is invalid";
print("Validation failed: $label is too short.");
return; // Skip the API call if input is invalid
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}");
return;
} else {
_clearError(field);
print("No duplicates found.");
}
} catch (e) {
print("Error in checkDuplicate: $e");
}
}
void _clearError(String field) {
setState(() {
widget.errorMessages.remove(field);
@ -1004,6 +1032,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
controller: widget.controllers["email"],
onChanged: (value) {
_clearError("email");
apiCheckDuplicate("Email", "email",value,widget.userIdApi);
},
enabled: !widget.isViewMode,
decoration: InputDecoration(
@ -1054,6 +1083,7 @@ class PersonalDetailsState extends State<PersonalDetails> {
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("mobile_no");
apiCheckDuplicate("Mobile Number", "mobile_no",value,widget.userIdApi);
},
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [

View File

@ -31,6 +31,8 @@ class TravellerDetails extends StatefulWidget {
final bool isViewMode;
final Map<String, dynamic>? travelDetails;
final String? passportFileUrlFromApi;
final String? userIdApi;
const TravellerDetails({
Key? key,
@ -40,6 +42,7 @@ class TravellerDetails extends StatefulWidget {
required this.isViewMode,
this.travelDetails,
this.passportFileUrlFromApi,
this.userIdApi,
}) : super(key: key);
@override
TravellerDetailsState createState() => TravellerDetailsState();
@ -146,6 +149,26 @@ class TravellerDetailsState extends State<TravellerDetails> {
});
}
Future<void> apiCheckDuplicate(String label, String field, String value, String? userId) async {
try {
if(field == "forex_card_num"){
field = "forex_pre_paid_card_number";
}
final response = await apiService.CheckDuplicate(label, field, value, userId);
if (response.isNotEmpty) {
_clearError(field);
widget.errorMessages[field] = response['message'] ?? "$label already exists";
print("Duplicate found: ${response['message']}");
return;
} else {
_clearError(field);
print("No duplicates found.");
}
} catch (e) {
print("Error in checkDuplicate: $e");
}
}
void _clearError(String field) {
setState(() {
widget.errorMessages.remove(field);
@ -2308,6 +2331,7 @@ class TravellerDetailsState extends State<TravellerDetails> {
enabled: !widget.isViewMode,
onChanged: (value) {
_clearError("forex_card_num");
apiCheckDuplicate("Forex Pre-Paid Card Number", "forex_card_num",value,widget.userIdApi);
},
decoration: InputDecoration(
labelText: "Card Number",
@ -2439,14 +2463,24 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(width: 25),
buildFrequentFlierInformation(entry),
SizedBox(width: 15),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
onPressed: () {
setState(() {
removeFrequentFlierEntry(entry);
});
},
SizedBox(
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
removeFrequentFlierEntry(entry);
});
},
),
),
),
),
],
)
: Column(
@ -2457,7 +2491,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildFrequentFlierInformation(entry),
SizedBox(width: 15),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
removeFrequentFlierEntry(entry);
@ -2738,22 +2773,30 @@ class TravellerDetailsState extends State<TravellerDetails> {
child:
widget.isDesktop
? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildHotel(entry),
SizedBox(width: 25),
buildHotelMembershipNum(entry),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
onPressed: () {
setState(() {
// removeHotelLoyaltyEntry(localId);
removeHotelLoyaltyEntry(entry);
});
},
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildHotel(entry),
SizedBox(width: 25),
buildHotelMembershipNum(entry),
SizedBox(
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
removeHotelLoyaltyEntry(entry);
});
},
),
),
],
)
),
),
],
)
: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -2761,7 +2804,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8),
buildHotelMembershipNum(entry),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
// removeHotelLoyaltyEntry(localId);
@ -2987,13 +3031,22 @@ class TravellerDetailsState extends State<TravellerDetails> {
buildVisaValidFrom(entry),
SizedBox(width: 15),
buildVisaValidUpTo(entry),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
onPressed: () {
setState(() {
removeVisaEntry(entry);
});
},
SizedBox(
height: 60,
child: Center(
child: Padding(
padding: EdgeInsets.only(top: 20, left: 8), // 👈 Add top padding here
child: IconButton(
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
removeVisaEntry(entry);
});
},
),
),
),
),
],
)
@ -3008,7 +3061,8 @@ class TravellerDetailsState extends State<TravellerDetails> {
SizedBox(height: 8),
buildVisaValidUpTo(entry),
IconButton(
icon: Icon(Icons.cancel, color: Colors.red, size: 15),
icon: Icon(Icons.horizontal_rule, color: Colors.red, size: 15),
tooltip: 'Cancel the Details',
onPressed: () {
setState(() {
// visaRowIds.remove(id);

View File

@ -1234,4 +1234,52 @@ class ApiService {
}
}
// ----------------------- User Management - CheckDuplicate ---------------
Future<Map<String, dynamic>> CheckDuplicate(String label, String field, String value, String? userId) async {
String apiUrldata;
if (userId == null || userId.isEmpty) {
apiUrldata = '$apiUrl/api/checkDuplicate?$field=$value';
} else {
apiUrldata = '$apiUrl/api/checkDuplicate?$field=$value&user_id=$userId';
}
final token = await getToken();
if (token == null) {
throw Exception('Token not found. Please log in.');
}
final response = await http.get(
Uri.parse(apiUrldata),
headers: {
'Authorization': 'Bearer $token',
'Content-Type': 'application/json',
},
);
if (response.statusCode == 200) {
try {
final data = json.decode(response.body);
// Updated to match actual response structure
if (data['status'] == "exists") {
print("${data['field']} - $value already exists");
return {
"message": "$label already exists",
"field": data['field']
};
} else {
print("$label - $value is a new value");
return {};
}
} catch (e) {
throw Exception('Error parsing response: $e');
}
} else {
throw Exception('Failed to load checkDuplicate data. Status code: ${response.statusCode}');
}
}
// ----------------------- User Management - CheckDuplicate end here ----------------------------------
}