APP-SIGNATURE
This commit is contained in:
parent
d29caf66c5
commit
f7342a14b4
@ -221,6 +221,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -253,6 +254,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
@ -308,6 +310,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -29,7 +29,8 @@ class _CommentModalListState extends State<CommentModalList> {
|
||||
Future<List<Map<String, dynamic>>> fetchComments1() async {
|
||||
final response = await http.get(
|
||||
Uri.parse(
|
||||
'$apiUrl/api/plans/getRemarksByPlanId?plan_id=${widget.planId}'),
|
||||
'$apiUrl/api/plans/getRemarksByPlanId?plan_id=${widget.planId}',
|
||||
),
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
@ -58,6 +59,7 @@ class _CommentModalListState extends State<CommentModalList> {
|
||||
Uri.parse(apiUrldata),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
@ -81,10 +83,7 @@ class _CommentModalListState extends State<CommentModalList> {
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
title: Text(
|
||||
'Comments',
|
||||
style: GoogleFonts.poppins(color: Colors.black),
|
||||
),
|
||||
title: Text('Comments', style: GoogleFonts.poppins(color: Colors.black)),
|
||||
content: ConstrainedBox(
|
||||
constraints: const BoxConstraints(
|
||||
maxWidth: 500, // ✅ You can adjust this width
|
||||
@ -119,64 +118,86 @@ class _CommentModalListState extends State<CommentModalList> {
|
||||
child: DataTable(
|
||||
columns: [
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Name',
|
||||
style:
|
||||
GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||
)),
|
||||
label: Text(
|
||||
'Name',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Comment',
|
||||
style:
|
||||
GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||
)),
|
||||
label: Text(
|
||||
'Comment',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataColumn(
|
||||
label: Text(
|
||||
'Updated On',
|
||||
style:
|
||||
GoogleFonts.poppins(fontSize: 11, color: Colors.black),
|
||||
)),
|
||||
label: Text(
|
||||
'Updated On',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
rows: comments.map((comment) {
|
||||
final name = comment['created_by_name'] ?? 'Unknown';
|
||||
final remark = comment['remarks'] ?? '';
|
||||
final rawDateStr = comment['updated_on'];
|
||||
String updatedOn = '';
|
||||
rows:
|
||||
comments.map((comment) {
|
||||
final name = comment['created_by_name'] ?? 'Unknown';
|
||||
final remark = comment['remarks'] ?? '';
|
||||
final rawDateStr = comment['updated_on'];
|
||||
String updatedOn = '';
|
||||
|
||||
if (rawDateStr != null && rawDateStr.isNotEmpty) {
|
||||
try {
|
||||
final parsedDate = DateTime.parse(rawDateStr);
|
||||
updatedOn = DateFormat('d MMM yyyy')
|
||||
.format(parsedDate); // e.g., 15 May 2025
|
||||
} catch (e) {
|
||||
updatedOn = rawDateStr.split(' ').first; // fallback
|
||||
}
|
||||
}
|
||||
if (rawDateStr != null && rawDateStr.isNotEmpty) {
|
||||
try {
|
||||
final parsedDate = DateTime.parse(rawDateStr);
|
||||
updatedOn = DateFormat(
|
||||
'd MMM yyyy',
|
||||
).format(parsedDate); // e.g., 15 May 2025
|
||||
} catch (e) {
|
||||
updatedOn = rawDateStr.split(' ').first; // fallback
|
||||
}
|
||||
}
|
||||
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(
|
||||
name,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500),
|
||||
)),
|
||||
DataCell(Text(
|
||||
remark,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500),
|
||||
)),
|
||||
DataCell(Text(
|
||||
updatedOn,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500),
|
||||
)),
|
||||
]);
|
||||
}).toList(),
|
||||
return DataRow(
|
||||
cells: [
|
||||
DataCell(
|
||||
Text(
|
||||
name,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
remark,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
updatedOn,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
@ -185,11 +206,14 @@ class _CommentModalListState extends State<CommentModalList> {
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text('Close',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: widget.layoutColorForUser)),
|
||||
child: Text(
|
||||
'Close',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: widget.layoutColorForUser,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@ -211,6 +211,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -243,6 +244,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
|
||||
@ -200,6 +200,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -233,6 +234,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
@ -293,6 +295,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -525,6 +528,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -117,6 +117,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Accept': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'email': _emailController.text.trim(),
|
||||
@ -214,11 +215,14 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
if (_isForgotPassword && !_showOtpResetFields) {
|
||||
print('11');
|
||||
// Step 1: Send OTP
|
||||
final url = '$apiUrl/forgotPassword/verifyUser';
|
||||
final url = '$apiUrl/api/forgotPassword/verifyUser';
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(url),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode({'email': _emailController.text.trim()}),
|
||||
);
|
||||
|
||||
@ -273,12 +277,15 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
} else if (!_isForgotPassword && _showOtpResetFields) {
|
||||
print('22');
|
||||
// Step 2: Verify OTP & Reset Password
|
||||
final url = '$apiUrl/forgotPassword/changePassword';
|
||||
final url = '$apiUrl/api/forgotPassword/changePassword';
|
||||
try {
|
||||
print('21');
|
||||
final response = await http.post(
|
||||
Uri.parse(url),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode({
|
||||
'email': _emailController.text.trim(),
|
||||
'otp': _otpController.text.trim(),
|
||||
@ -1111,12 +1118,15 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
}
|
||||
|
||||
Future<void> handleMS() async {
|
||||
final url = '$apiUrl/auth/mslogin';
|
||||
final url = '$apiUrl/api/auth/mslogin';
|
||||
print(url);
|
||||
try {
|
||||
final response = await http.get(
|
||||
Uri.parse(url),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
print("inside try method");
|
||||
if (response.statusCode == 200) {
|
||||
|
||||
@ -105,6 +105,7 @@ class CostCenterDataState extends State<CostCenterData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -168,7 +169,7 @@ class CostCenterDataState extends State<CostCenterData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postCostCenterData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -212,6 +213,7 @@ class CostCenterDataState extends State<CostCenterData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(costcenterData);
|
||||
|
||||
@ -426,22 +428,23 @@ class CostCenterDataState extends State<CostCenterData> {
|
||||
// ),
|
||||
SizedBox(
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// onPressed: () {
|
||||
// handleSubmit();
|
||||
// // You can get text from commentController.text
|
||||
|
||||
@ -149,6 +149,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
print("called api : $apiUrlData");
|
||||
@ -286,15 +287,13 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Cost Center Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Cost Center Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -310,8 +309,8 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.08),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -458,7 +457,7 @@ class CostCenterListState extends State<CostCenterList> {
|
||||
builder: (context, snapshot) {
|
||||
final adjHgt = MediaQuery.of(context).size.height;
|
||||
if (futureCostCenter == null) {
|
||||
return CircularProgressIndicator();
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
|
||||
@ -205,6 +205,7 @@ class StatusDashboardState extends State<StatusDashboard> {
|
||||
Uri.parse(apiUrlData),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
@ -105,6 +105,7 @@ class DepartmentDataState extends State<DepartmentData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -168,7 +169,7 @@ class DepartmentDataState extends State<DepartmentData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postDepartmentData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -212,6 +213,7 @@ class DepartmentDataState extends State<DepartmentData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(departmentData);
|
||||
|
||||
@ -428,22 +430,23 @@ class DepartmentDataState extends State<DepartmentData> {
|
||||
// ),
|
||||
SizedBox(
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -149,6 +149,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
print("called api : $apiUrlData");
|
||||
@ -181,11 +182,10 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
allDepartment.where((object) {
|
||||
final isActiveStatus =
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['id']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
return (object['id']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
// (object['description']?.toLowerCase().contains(lowerQuery) ??
|
||||
// false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
@ -285,15 +285,13 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Department Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Department Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -309,8 +307,8 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.08),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -584,8 +582,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
rows:
|
||||
paginatedDepartment.map((tableObject) {
|
||||
String departmentId =
|
||||
tableObject['id']
|
||||
.toString(); // Get user ID
|
||||
tableObject['id'].toString(); // Get user ID
|
||||
bool isSelected =
|
||||
selectedDepartmentId == departmentId;
|
||||
|
||||
@ -648,8 +645,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final departmentId = int.tryParse(
|
||||
tableObject['id']
|
||||
.toString(),
|
||||
tableObject['id'].toString(),
|
||||
);
|
||||
|
||||
if (departmentId != null) {
|
||||
@ -741,8 +737,7 @@ class DepartmentListState extends State<DepartmentList> {
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final departmentId = int.tryParse(
|
||||
cardObject['id']
|
||||
.toString(),
|
||||
cardObject['id'].toString(),
|
||||
);
|
||||
|
||||
if (departmentId != null) {
|
||||
|
||||
@ -71,6 +71,7 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -95,7 +96,6 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
_users = userList.map((user) => SearchUser.fromJson(user)).toList();
|
||||
_filteredUsers = List.from(_users);
|
||||
_filterUsers("");
|
||||
|
||||
});
|
||||
print("filtered user === ${_filteredUsers.length}");
|
||||
print("Users fetched: ${_users.length}");
|
||||
@ -132,6 +132,7 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -211,10 +212,15 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
|
||||
if (query.isEmpty) {
|
||||
// ✅ Return all users excluding self and roleId == 5
|
||||
_filteredList = _users.where((user) =>
|
||||
user.userId.toString() != excludedUserId && user.roleId.toString() != "5")
|
||||
.map((user) => {"type": "user", "data": user})
|
||||
.toList();
|
||||
_filteredList =
|
||||
_users
|
||||
.where(
|
||||
(user) =>
|
||||
user.userId.toString() != excludedUserId &&
|
||||
user.roleId.toString() != "5",
|
||||
)
|
||||
.map((user) => {"type": "user", "data": user})
|
||||
.toList();
|
||||
|
||||
// _filteredList = [
|
||||
// // ..._users.map((user) => {"type": "user", "data": user}),
|
||||
@ -277,9 +283,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
setState(() {
|
||||
_filteredList.clear(); // Reset the list before filtering
|
||||
if (query.isEmpty) {
|
||||
_filteredList = _traveller
|
||||
.map((traveller) => {"type": "traveller", "data": traveller})
|
||||
.toList();
|
||||
_filteredList =
|
||||
_traveller
|
||||
.map((traveller) => {"type": "traveller", "data": traveller})
|
||||
.toList();
|
||||
// _filteredList = [
|
||||
// ..._users.map((user) => {"type": "user", "data": user}),
|
||||
// ];
|
||||
@ -377,19 +384,21 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.title == "Others (Non Employee)"){ fetchTraveller(); }
|
||||
else{ fetchUsers(); }
|
||||
if (widget.title == "Others (Non Employee)") {
|
||||
fetchTraveller();
|
||||
} else {
|
||||
fetchUsers();
|
||||
}
|
||||
print("SelffsdfcurrentUser - ${widget.currentUser}");
|
||||
_filterByTitle("");
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
final isValid = _searchController.text.trim().isNotEmpty &&
|
||||
final isValid =
|
||||
_searchController.text.trim().isNotEmpty &&
|
||||
userIdSelected.trim().isNotEmpty;
|
||||
|
||||
|
||||
return Dialog(
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
|
||||
child: Container(
|
||||
@ -482,81 +491,100 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
// _searchController.text.isNotEmpty
|
||||
// ?
|
||||
if (!_showTravellerForm)
|
||||
SizedBox(
|
||||
height: 300, // Limit height to avoid overflow
|
||||
// child: _filteredUsers.isEmpty
|
||||
child:
|
||||
_filteredList.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No users found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
SizedBox(
|
||||
height: 300, // Limit height to avoid overflow
|
||||
// child: _filteredUsers.isEmpty
|
||||
child:
|
||||
_filteredList.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No users found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
// itemCount: _filteredUsers.length,
|
||||
itemCount: _filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
// final user = _filteredUsers[index];
|
||||
|
||||
final item = _filteredList[index];
|
||||
final user = item["data"]; // Extract user object
|
||||
final userType =
|
||||
item["type"]; // "user" or "traveller"
|
||||
if (user is Map<String, dynamic>) {
|
||||
print("userLsirer - ${jsonEncode(user)}"); // pretty JSON-like string
|
||||
} else {
|
||||
print("userLsirer - $user"); // fallback
|
||||
}
|
||||
final isSelected = userIdSelected == (userType == "user" ? user.userId : user.travellerId);
|
||||
return ListTile(
|
||||
// hoverColor: ,
|
||||
title: Text(
|
||||
"${user.firstName ?? "Unknown"}" "${(user.lastName?.isNotEmpty ?? false) ? " ${user.lastName}" : ""}",
|
||||
style: GoogleFonts.poppins(fontSize: 11 , color: isSelected ? widget.layoutColorForUser : Colors.black),
|
||||
),
|
||||
subtitle:
|
||||
userType == "user"
|
||||
? Text(
|
||||
"Employee ID: ${user.empCode ?? "-"} ",
|
||||
// "Employee ID: ${userType == "user" ? user.userId : user.travellerId}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: isSelected ? widget.layoutColorForUser : Colors.black,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
"Mobile : ${user.mobileNo ?? "-"} ",
|
||||
// "Employee ID: ${userType == "user" ? user.userId : user.travellerId}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: isSelected ? widget.layoutColorForUser : Colors.black,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
String selectedUser =
|
||||
"${user.firstName ?? "Unknown"} ${user.lastName ?? ""}";
|
||||
setState(() {
|
||||
_searchController.text = selectedUser;
|
||||
userIdSelected =
|
||||
userType == "user"
|
||||
? user.userId
|
||||
: user.travellerId;
|
||||
isTraveller = userType == "traveller";
|
||||
});
|
||||
print(
|
||||
"Selected: $selectedUser, ID: ${userType == "user" ? user.userId : user.travellerId},"
|
||||
" isTraveller: $userIdSelected",
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// : SizedBox.shrink(),
|
||||
)
|
||||
: ListView.builder(
|
||||
// itemCount: _filteredUsers.length,
|
||||
itemCount: _filteredList.length,
|
||||
itemBuilder: (context, index) {
|
||||
// final user = _filteredUsers[index];
|
||||
|
||||
final item = _filteredList[index];
|
||||
final user = item["data"]; // Extract user object
|
||||
final userType =
|
||||
item["type"]; // "user" or "traveller"
|
||||
if (user is Map<String, dynamic>) {
|
||||
print(
|
||||
"userLsirer - ${jsonEncode(user)}",
|
||||
); // pretty JSON-like string
|
||||
} else {
|
||||
print("userLsirer - $user"); // fallback
|
||||
}
|
||||
final isSelected =
|
||||
userIdSelected ==
|
||||
(userType == "user"
|
||||
? user.userId
|
||||
: user.travellerId);
|
||||
return ListTile(
|
||||
// hoverColor: ,
|
||||
title: Text(
|
||||
"${user.firstName ?? "Unknown"}"
|
||||
"${(user.lastName?.isNotEmpty ?? false) ? " ${user.lastName}" : ""}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color:
|
||||
isSelected
|
||||
? widget.layoutColorForUser
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
subtitle:
|
||||
userType == "user"
|
||||
? Text(
|
||||
"Employee ID: ${user.empCode ?? "-"} ",
|
||||
// "Employee ID: ${userType == "user" ? user.userId : user.travellerId}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color:
|
||||
isSelected
|
||||
? widget.layoutColorForUser
|
||||
: Colors.black,
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
"Mobile : ${user.mobileNo ?? "-"} ",
|
||||
// "Employee ID: ${userType == "user" ? user.userId : user.travellerId}",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color:
|
||||
isSelected
|
||||
? widget.layoutColorForUser
|
||||
: Colors.black,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
String selectedUser =
|
||||
"${user.firstName ?? "Unknown"} ${user.lastName ?? ""}";
|
||||
setState(() {
|
||||
_searchController.text = selectedUser;
|
||||
userIdSelected =
|
||||
userType == "user"
|
||||
? user.userId
|
||||
: user.travellerId;
|
||||
isTraveller = userType == "traveller";
|
||||
});
|
||||
print(
|
||||
"Selected: $selectedUser, ID: ${userType == "user" ? user.userId : user.travellerId},"
|
||||
" isTraveller: $userIdSelected",
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
// : SizedBox.shrink(),
|
||||
|
||||
// Traveler Form
|
||||
if (_showTravellerForm)
|
||||
@ -616,32 +644,35 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
|
||||
SizedBox(width: 10),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: isValid ? widget.layoutColorForUser : Colors.grey,
|
||||
backgroundColor:
|
||||
isValid ? widget.layoutColorForUser : Colors.grey,
|
||||
foregroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(
|
||||
// color: widget.layoutColorForUser,
|
||||
color: isValid ? widget.layoutColorForUser : Colors.grey,
|
||||
color:
|
||||
isValid ? widget.layoutColorForUser : Colors.grey,
|
||||
width: isValid ? 2 : 0,
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: isValid ? () {
|
||||
print("Submitting: ${_searchController.text}, ID: $userIdSelected");
|
||||
widget.onSubmit(
|
||||
_searchController.text,
|
||||
userIdSelected,
|
||||
isTraveller,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
: null,
|
||||
child: Text(
|
||||
"Save",
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
onPressed:
|
||||
isValid
|
||||
? () {
|
||||
print(
|
||||
"Submitting: ${_searchController.text}, ID: $userIdSelected",
|
||||
);
|
||||
widget.onSubmit(
|
||||
_searchController.text,
|
||||
userIdSelected,
|
||||
isTraveller,
|
||||
);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
: null,
|
||||
child: Text("Save", style: GoogleFonts.poppins(fontSize: 11)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -745,6 +776,7 @@ class _TravelerFormState extends State<TravelerForm> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(requestBody),
|
||||
);
|
||||
|
||||
@ -247,6 +247,7 @@ class _groupState extends State<Group> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(groupData),
|
||||
)
|
||||
@ -255,6 +256,7 @@ class _groupState extends State<Group> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(groupData),
|
||||
));
|
||||
|
||||
@ -232,7 +232,7 @@ class GroupDataState extends State<GroupData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postGroupData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -270,6 +270,7 @@ class GroupDataState extends State<GroupData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(groupData);
|
||||
|
||||
@ -308,12 +309,12 @@ class GroupDataState extends State<GroupData> {
|
||||
behavior: SnackBarBehavior.floating,
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
final message = jsonDecode(response.body);
|
||||
final errorMessage = message['messages']?['error'] ?? 'Unknown error occurred';
|
||||
final errorMessage =
|
||||
message['messages']?['error'] ?? 'Unknown error occurred';
|
||||
|
||||
if (errorMessage.contains("Duplicate entry")) {
|
||||
_clearError();
|
||||
@ -464,7 +465,11 @@ class GroupDataState extends State<GroupData> {
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_circle_sharp, size: 12, color: Colors.redAccent),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
size: 12,
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
tooltip: "Reset",
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -506,15 +511,15 @@ class GroupDataState extends State<GroupData> {
|
||||
constraints: BoxConstraints(maxHeight: 250),
|
||||
itemBuilder:
|
||||
(context, object, isSelected) => Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 6.0,
|
||||
),
|
||||
child: Text(
|
||||
object,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 6.0,
|
||||
),
|
||||
child: Text(
|
||||
object,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
),
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
@ -533,40 +538,47 @@ class GroupDataState extends State<GroupData> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["domestic_policy_nameFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
(focusStates["domestic_policy_nameFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["domestic_policy_nameFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
(focusStates["domestic_policy_nameFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
// width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
borderSide: BorderSide(
|
||||
color: widget.layoutColor!,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
vertical: 8.0,),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
// Center-align selected item
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select ",
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
// Center-align selected item
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select ",
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
@ -574,7 +586,7 @@ class GroupDataState extends State<GroupData> {
|
||||
DomesticMap.entries
|
||||
.firstWhere(
|
||||
(entry) => entry.value == newValue,
|
||||
)
|
||||
)
|
||||
.key;
|
||||
selectedDomesticPolicyName = newValue;
|
||||
});
|
||||
@ -602,7 +614,11 @@ class GroupDataState extends State<GroupData> {
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_circle_sharp, size: 12, color: Colors.redAccent),
|
||||
icon: Icon(
|
||||
Icons.remove_circle_sharp,
|
||||
size: 12,
|
||||
color: Colors.redAccent,
|
||||
),
|
||||
tooltip: "Reset",
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
@ -673,28 +689,35 @@ class GroupDataState extends State<GroupData> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["international_policy_nameFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
(focusStates["international_policy_nameFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["international_policy_nameFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
(focusStates["international_policy_nameFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
borderSide: BorderSide(
|
||||
color: widget.layoutColor!,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
vertical: 8.0,),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||
),
|
||||
),
|
||||
@ -833,21 +856,22 @@ class GroupDataState extends State<GroupData> {
|
||||
// // You can get text from commentController.text
|
||||
// // Navigator.of(context).pop(); // Close the modal
|
||||
// },
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -190,6 +190,7 @@ class _GroupListState extends State<GroupList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode({
|
||||
"is_active": newStatus, // Set new status dynamically
|
||||
@ -304,18 +305,17 @@ class _GroupListState extends State<GroupList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Group ',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Group '),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Text(
|
||||
// 'Group',
|
||||
// style: GoogleFonts.poppins(
|
||||
@ -324,13 +324,12 @@ class _GroupListState extends State<GroupList> {
|
||||
// color: Colors.black,
|
||||
// ),
|
||||
// ),
|
||||
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.145),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.28),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.28),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -625,7 +624,9 @@ class _GroupListState extends State<GroupList> {
|
||||
// ),
|
||||
DataCell(
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 200), // limit description width
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 200,
|
||||
), // limit description width
|
||||
child: Text(
|
||||
"${group['name'] ?? ''}",
|
||||
style: TextStyle(
|
||||
@ -633,7 +634,8 @@ class _GroupListState extends State<GroupList> {
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 1, // optional: show only 1 line
|
||||
maxLines:
|
||||
1, // optional: show only 1 line
|
||||
softWrap: false,
|
||||
),
|
||||
),
|
||||
@ -667,7 +669,9 @@ class _GroupListState extends State<GroupList> {
|
||||
// ),
|
||||
DataCell(
|
||||
ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: 200), // limit description width
|
||||
constraints: BoxConstraints(
|
||||
maxWidth: 200,
|
||||
), // limit description width
|
||||
child: Text(
|
||||
"${group['description'] ?? 'N/A'}",
|
||||
style: TextStyle(
|
||||
|
||||
@ -120,6 +120,7 @@ class HotelsDataState extends State<HotelsData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -201,7 +202,7 @@ class HotelsDataState extends State<HotelsData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postHotelsData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -247,6 +248,7 @@ class HotelsDataState extends State<HotelsData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(hotelsData);
|
||||
|
||||
@ -282,7 +284,6 @@ class HotelsDataState extends State<HotelsData> {
|
||||
setState(() {
|
||||
isDisable = false;
|
||||
});
|
||||
|
||||
} else {
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
@ -291,14 +292,12 @@ class HotelsDataState extends State<HotelsData> {
|
||||
isDisable = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
} catch (e) {
|
||||
print("Error submitting plan: $e");
|
||||
setState(() {
|
||||
isDisable = false;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@override
|
||||
@ -318,7 +317,7 @@ class HotelsDataState extends State<HotelsData> {
|
||||
countryMap = {
|
||||
for (var country in countryList)
|
||||
(country['country_code'] ?? ''):
|
||||
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
|
||||
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
|
||||
};
|
||||
|
||||
// Extract only country codes for processing
|
||||
@ -455,7 +454,9 @@ class HotelsDataState extends State<HotelsData> {
|
||||
focusNode: focusNodes["categoryFocusNode"],
|
||||
controller: controllers["category"],
|
||||
inputFormatters: [
|
||||
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 ]')),
|
||||
FilteringTextInputFormatter.allow(
|
||||
RegExp(r'[a-zA-Z0-9 ]'),
|
||||
),
|
||||
],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
@ -489,119 +490,144 @@ class HotelsDataState extends State<HotelsData> {
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: double.infinity,
|
||||
child: Focus(
|
||||
focusNode: focusNodes["country_codeFocusNode"],
|
||||
onFocusChange: (hasFocus) {
|
||||
setState(() {
|
||||
focusStates["country_codeFocused"] = hasFocus;
|
||||
});
|
||||
width: double.infinity,
|
||||
child: Focus(
|
||||
focusNode: focusNodes["country_codeFocusNode"],
|
||||
onFocusChange: (hasFocus) {
|
||||
setState(() {
|
||||
focusStates["country_codeFocused"] = hasFocus;
|
||||
});
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Request focus when user taps
|
||||
focusNodes["country_codeFocusNode"]?.requestFocus();
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Request focus when user taps
|
||||
focusNodes["country_codeFocusNode"]?.requestFocus();
|
||||
},
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: countryMap[selectedCountry],
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true, // Enables search functionality
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) {
|
||||
print("contryItem - $item");
|
||||
final match = RegExp(r'^(.*)\s\((.*)\)$',).firstMatch(item);
|
||||
final countryName = match?.group(1) ?? '';
|
||||
final countryCode = match?.group(2) ?? '';
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 0.02,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
countryName,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
Text(
|
||||
countryCode,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5,color:Colors.grey),
|
||||
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);},
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 1,vertical: 1),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: countryMap.values.toList(),
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
// width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
vertical: 8.0,),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
// Center-align selected item
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select ",
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedCountry =
|
||||
countryMap.entries
|
||||
.firstWhere((entry) => entry.value == newValue)
|
||||
.key;
|
||||
final match = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(newValue!);
|
||||
final countryName = match?.group(1) ?? newValue; // --> "Ascension Islands"
|
||||
// final countryCode = match?.group(2) ?? "";
|
||||
selectedCountryName = countryName;
|
||||
});
|
||||
},
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: countryMap[selectedCountry],
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true, // Enables search functionality
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
)
|
||||
)
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder: (context, item, isSelected) {
|
||||
print("contryItem - $item");
|
||||
final match = RegExp(
|
||||
r'^(.*)\s\((.*)\)$',
|
||||
).firstMatch(item);
|
||||
final countryName = match?.group(1) ?? '';
|
||||
final countryCode = match?.group(2) ?? '';
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 0.02,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
countryName,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
countryCode,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 1,
|
||||
vertical: 1,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
items: countryMap.values.toList(),
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
// width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: widget.layoutColor!,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
// Center-align selected item
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
selectedItem ?? "Select ",
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedCountry =
|
||||
countryMap.entries
|
||||
.firstWhere(
|
||||
(entry) => entry.value == newValue,
|
||||
)
|
||||
.key;
|
||||
final match = RegExp(
|
||||
r'^(.*)\s\((.*)\)$',
|
||||
).firstMatch(newValue!);
|
||||
final countryName =
|
||||
match?.group(1) ??
|
||||
newValue; // --> "Ascension Islands"
|
||||
// final countryCode = match?.group(2) ?? "";
|
||||
selectedCountryName = countryName;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["country_code"] != null) ...[
|
||||
@ -712,22 +738,23 @@ class HotelsDataState extends State<HotelsData> {
|
||||
// ),
|
||||
SizedBox(
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -152,6 +152,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -177,6 +178,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -338,15 +340,13 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Hotel Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Hotel Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -508,7 +508,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
builder: (context, snapshot) {
|
||||
final adjHgt = MediaQuery.of(context).size.height;
|
||||
if (futureHotels == null) {
|
||||
return CircularProgressIndicator();
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
@ -892,7 +892,7 @@ class HotelsDataListState extends State<HotelsDataList> {
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"${hotels['category'] ?? ''} ",
|
||||
|
||||
@ -207,6 +207,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(forexData), // Convert map to JSON
|
||||
);
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:html' as html;
|
||||
import 'dart:async';
|
||||
import 'dart:io' as io show Directory, File;
|
||||
import 'package:delta_to_html/delta_to_html.dart';
|
||||
import 'package:flutter/cupertino.dart' as dom;
|
||||
@ -15,6 +17,9 @@ import 'package:frontend/Screens/myTemplates/templateForex.dart'
|
||||
as _editorScrollController;
|
||||
import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller;
|
||||
import 'package:html2md/html2md.dart' as html2md;
|
||||
import 'package:http_parser/http_parser.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:mime/mime.dart';
|
||||
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
|
||||
|
||||
import 'package:flutter_quill/flutter_quill.dart' as quill;
|
||||
@ -59,6 +64,8 @@ class TemplateForex extends StatefulWidget {
|
||||
class TemplateForexState extends State<TemplateForex> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
Uint8List? _imageBytes;
|
||||
String? selectedOrglogo;
|
||||
// final QuillController _controller = QuillController.basic();
|
||||
String? orgId;
|
||||
String? userId;
|
||||
@ -91,11 +98,6 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
"body_html": DeltaToHTML.encodeJson(
|
||||
_controller.document.toDelta().toJson(),
|
||||
),
|
||||
// "body_html": jsonEncode(_controller.document.toDelta().toJson()),
|
||||
|
||||
// "body_html": _controller,
|
||||
// "body_html": convertQuillDocToHtml(_controller.document),
|
||||
// ✅ convert delta to HTML
|
||||
"placeholder": jsonEncode(placeholderList),
|
||||
// "created_by": userId
|
||||
};
|
||||
@ -363,7 +365,7 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
print(
|
||||
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}",
|
||||
);
|
||||
setState(() {
|
||||
setState(() async {
|
||||
// ✅ Wrap in setState to update the UI
|
||||
controllers["templateName"]?.text =
|
||||
widget.templateData?["templateData"]?["template_name"] ?? "";
|
||||
@ -432,7 +434,7 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
) ??
|
||||
0;
|
||||
print("Fetched template_id: $templateId");
|
||||
|
||||
fetchSignature();
|
||||
// if (widget.group?["international_policy_id"] != null) {
|
||||
// selectedInternational =
|
||||
// widget.group!["international_policy_id"].toString();
|
||||
@ -443,6 +445,34 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> fetchSignature() async {
|
||||
final uri = Uri.parse('$apiUrl/api/getForexSignaturePath');
|
||||
final token = await getToken();
|
||||
|
||||
final response = await http.get(
|
||||
uri,
|
||||
headers: {'Authorization': 'Bearer $token'},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print("ERS - $response");
|
||||
final json = jsonDecode(response.body);
|
||||
|
||||
print("ERSjson - $json");
|
||||
|
||||
String? rawLogoPath = json['url']?.toString();
|
||||
|
||||
if (rawLogoPath != null && rawLogoPath.isNotEmpty) {
|
||||
print("ERSrawLogoPath - $rawLogoPath");
|
||||
setState(() {
|
||||
selectedOrglogo = rawLogoPath;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
print("❌ Failed to fetch signature: ${response.statusCode}");
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> handleSubmit() async {
|
||||
Map<String, dynamic> data = TemplateData;
|
||||
|
||||
@ -492,6 +522,7 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(policyData), // Convert map to JSON
|
||||
);
|
||||
@ -519,6 +550,70 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _pickImage() async {
|
||||
final picker = ImagePicker();
|
||||
final XFile? pickedFile = await picker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
);
|
||||
|
||||
if (pickedFile != null && kIsWeb) {
|
||||
try {
|
||||
final bytes = await pickedFile.readAsBytes();
|
||||
print('✅ Image loaded, size: ${bytes.length} bytes');
|
||||
setState(() {
|
||||
_imageBytes = bytes;
|
||||
});
|
||||
await uploadSignature();
|
||||
} catch (e) {
|
||||
print('❌ Error reading image bytes: $e');
|
||||
}
|
||||
} else {
|
||||
print('⚠️ Image picking canceled or not on web.');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> uploadSignature() async {
|
||||
if (_imageBytes == null) {
|
||||
print('⚠️ No image selected');
|
||||
return;
|
||||
}
|
||||
|
||||
final token = await getToken(); // Fetch token
|
||||
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
final uri = Uri.parse('$apiUrl/api/forex_signature_upload');
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
|
||||
// Add auth header
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
|
||||
// Add the image as multipart with the key "signature"
|
||||
request.files.add(
|
||||
http.MultipartFile.fromBytes(
|
||||
'signature', // <-- key name
|
||||
_imageBytes!, // <-- image bytes
|
||||
filename: 'signature.png', // <-- filename (can be png/jpg)
|
||||
contentType: MediaType('image', 'png'),
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
final response = await request.send();
|
||||
final respStr = await response.stream.bytesToString();
|
||||
|
||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||
print('✅ Upload successful: $respStr');
|
||||
} else {
|
||||
print('❌ Upload failed (${response.statusCode}): $respStr');
|
||||
}
|
||||
} catch (e) {
|
||||
print('❌ Error uploading signature: $e');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(
|
||||
@ -683,56 +778,65 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
|
||||
child: IconTheme(
|
||||
data: IconThemeData(size: 18), // Set icon size here
|
||||
child: QuillSimpleToolbar(
|
||||
controller: _controller,
|
||||
config: QuillSimpleToolbarConfig(
|
||||
embedButtons: FlutterQuillEmbeds.toolbarButtons(),
|
||||
showClipboardPaste: true,
|
||||
customButtons: [
|
||||
QuillToolbarCustomButtonOptions(
|
||||
icon: const Icon(Icons.add_alarm_rounded),
|
||||
onPressed: () {
|
||||
_controller.document.insert(
|
||||
_controller.selection.extentOffset,
|
||||
TimeStampEmbed(DateTime.now().toString()),
|
||||
);
|
||||
|
||||
_controller.updateSelection(
|
||||
TextSelection.collapsed(
|
||||
offset: _controller.selection.extentOffset + 1,
|
||||
),
|
||||
ChangeSource.local,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
buttonOptions: QuillSimpleToolbarButtonOptions(
|
||||
base: QuillToolbarBaseButtonOptions(
|
||||
afterButtonPressed: () {
|
||||
final isDesktop = {
|
||||
TargetPlatform.linux,
|
||||
TargetPlatform.windows,
|
||||
TargetPlatform.macOS,
|
||||
}.contains(defaultTargetPlatform);
|
||||
// if (isDesktop) {
|
||||
// _editorFocusNode.requestFocus();
|
||||
// }
|
||||
},
|
||||
),
|
||||
linkStyle: QuillToolbarLinkStyleButtonOptions(
|
||||
validateLink: (link) {
|
||||
// Treats all links as valid. When launching the URL,
|
||||
// `https://` is prefixed if the link is incomplete (e.g., `google.com` → `https://google.com`)
|
||||
// however this happens only within the editor.
|
||||
return true;
|
||||
},
|
||||
),
|
||||
),
|
||||
child: Container(
|
||||
color: Color(0xFFFFFEF0),
|
||||
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
|
||||
child: IconTheme(
|
||||
data: IconThemeData(size: 18), // Set icon size here
|
||||
child: QuillSimpleToolbar(controller: _controller),
|
||||
),
|
||||
),
|
||||
// child: QuillSimpleToolbar(
|
||||
// controller: _controller,
|
||||
// config: QuillSimpleToolbarConfig(
|
||||
// embedButtons: FlutterQuillEmbeds.toolbarButtons(),
|
||||
// showClipboardPaste: true,
|
||||
// customButtons: [
|
||||
// QuillToolbarCustomButtonOptions(
|
||||
// icon: const Icon(Icons.add_alarm_rounded),
|
||||
// onPressed: () {
|
||||
// _controller.document.insert(
|
||||
// _controller.selection.extentOffset,
|
||||
// TimeStampEmbed(DateTime.now().toString()),
|
||||
// );
|
||||
//
|
||||
// _controller.updateSelection(
|
||||
// TextSelection.collapsed(
|
||||
// offset: _controller.selection.extentOffset + 1,
|
||||
// ),
|
||||
// ChangeSource.local,
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// buttonOptions: QuillSimpleToolbarButtonOptions(
|
||||
// base: QuillToolbarBaseButtonOptions(
|
||||
// afterButtonPressed: () {
|
||||
// final isDesktop = {
|
||||
// TargetPlatform.linux,
|
||||
// TargetPlatform.windows,
|
||||
// TargetPlatform.macOS,
|
||||
// }.contains(defaultTargetPlatform);
|
||||
// // if (isDesktop) {
|
||||
// // _editorFocusNode.requestFocus();
|
||||
// // }
|
||||
// },
|
||||
// ),
|
||||
// linkStyle: QuillToolbarLinkStyleButtonOptions(
|
||||
// validateLink: (link) {
|
||||
// // Treats all links as valid. When launching the URL,
|
||||
// // `https://` is prefixed if the link is incomplete (e.g., `google.com` → `https://google.com`)
|
||||
// // however this happens only within the editor.
|
||||
// return true;
|
||||
// },
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(height: 2),
|
||||
Container(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
@ -782,9 +886,10 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
height: MediaQuery.of(context).size.height * 0.45,
|
||||
height: MediaQuery.of(context).size.height * 0.38,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Color(0xFFD6D5E6), width: 0.5),
|
||||
@ -799,15 +904,16 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
padding: const EdgeInsets.all(16),
|
||||
embedBuilders: [
|
||||
...FlutterQuillEmbeds.editorBuilders(
|
||||
imageEmbedConfig: QuillEditorImageEmbedConfig(
|
||||
imageProviderBuilder: (context, imageUrl) {
|
||||
// https://pub.dev/packages/flutter_quill_extensions#-image-assets
|
||||
if (imageUrl.startsWith('assets/')) {
|
||||
return AssetImage(imageUrl);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
// imageEmbedConfig: QuillEditorImageEmbedConfig(
|
||||
// imageProviderBuilder: (context, imageUrl) {
|
||||
// if (imageUrl.startsWith('data:image')) {
|
||||
// return MemoryImage(
|
||||
// base64Decode(imageUrl.split(',').last),
|
||||
// );
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// ),
|
||||
videoEmbedConfig: QuillEditorVideoEmbedConfig(
|
||||
customVideoBuilder: (videoUrl, readOnly) {
|
||||
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
|
||||
@ -820,6 +926,58 @@ class TemplateForexState extends State<TemplateForex> {
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 4),
|
||||
Container(
|
||||
child: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
"Upload Signature",
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
SizedBox(width: 5),
|
||||
GestureDetector(
|
||||
onTap: _pickImage,
|
||||
|
||||
child:
|
||||
_imageBytes != null
|
||||
? ClipOval(
|
||||
child: Image.memory(
|
||||
_imageBytes!,
|
||||
// width: 50,
|
||||
// height: 50,
|
||||
width: 50, // Use responsive width
|
||||
height: 50,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
)
|
||||
: selectedOrglogo != null
|
||||
? ClipRect(
|
||||
child: Image.network(
|
||||
selectedOrglogo!,
|
||||
width: 50, // Use responsive width
|
||||
height: 50,
|
||||
// width: 250,
|
||||
// height: 55,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: Colors.redAccent,
|
||||
child: Icon(Icons.error, size: 10),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: Colors.amber,
|
||||
child: Icon(Icons.add_a_photo, size: 10),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@ -178,6 +178,7 @@ class TemplatesListState extends State<TemplatesList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -210,6 +211,7 @@ class TemplatesListState extends State<TemplatesList> {
|
||||
// Use MultipartRequest (POST only)
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
|
||||
@ -447,24 +449,22 @@ class TemplatesListState extends State<TemplatesList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Templates',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Templates'),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.13),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.23),
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.13),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.23),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -597,7 +597,7 @@ class TemplatesListState extends State<TemplatesList> {
|
||||
builder: (context, snapshot) {
|
||||
final adjHgt = MediaQuery.of(context).size.height;
|
||||
if (futureTemplates == null) {
|
||||
return CircularProgressIndicator();
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
|
||||
@ -50,6 +50,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Map<String, dynamic> getMailData() => mailData;
|
||||
|
||||
Map<String, dynamic> get mailData {
|
||||
@ -169,6 +170,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(mailData), // Convert map to JSON
|
||||
);
|
||||
@ -353,7 +355,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if(isDesktop) SizedBox(width:20),
|
||||
if (isDesktop) SizedBox(width: 20),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, // ✅ This works
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -447,9 +449,9 @@ class _MailSettingState extends State<MailSetting> {
|
||||
isFocused: focusStates["senderEmailFocused"] ?? false,
|
||||
isDesktop: widget.isDesktop,
|
||||
width:
|
||||
widget.isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.23
|
||||
: MediaQuery.of(context).size.width * 0.85,
|
||||
widget.isDesktop
|
||||
? MediaQuery.of(context).size.width * 0.23
|
||||
: MediaQuery.of(context).size.width * 0.85,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
@ -465,8 +467,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
} else if (!RegExp(
|
||||
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
|
||||
).hasMatch(value)) {
|
||||
errorMessages["sender_email"] =
|
||||
"Invalid email format";
|
||||
errorMessages["sender_email"] = "Invalid email format";
|
||||
}
|
||||
},
|
||||
style: GoogleFonts.poppins(fontSize: 12),
|
||||
@ -492,7 +493,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if(isDesktop) SizedBox(width:20),
|
||||
if (isDesktop) SizedBox(width: 20),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, // ✅ This works
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@ -545,7 +546,7 @@ class _MailSettingState extends State<MailSetting> {
|
||||
],
|
||||
],
|
||||
),
|
||||
if(isDesktop) SizedBox(width:20),
|
||||
if (isDesktop) SizedBox(width: 20),
|
||||
Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween, // ✅ This works
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
@ -333,6 +333,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
||||
// Use MultipartRequest (POST only)
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
if (isUpdating) {
|
||||
|
||||
@ -130,6 +130,7 @@ class ForexDataState extends State<ForexData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -247,7 +248,7 @@ class ForexDataState extends State<ForexData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postForexData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -256,7 +257,6 @@ class ForexDataState extends State<ForexData> {
|
||||
print("ForexDAta - $forexData1");
|
||||
}
|
||||
|
||||
|
||||
Future<void> postForexData({int isActive = 1}) async {
|
||||
// final remarksData = getData();
|
||||
|
||||
@ -296,6 +296,7 @@ class ForexDataState extends State<ForexData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(forexData);
|
||||
|
||||
@ -375,7 +376,7 @@ class ForexDataState extends State<ForexData> {
|
||||
countryMap = {
|
||||
for (var country in countryList)
|
||||
(country['country_code'] ?? ''):
|
||||
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
|
||||
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
|
||||
};
|
||||
|
||||
// Extract only country codes for processing
|
||||
@ -435,105 +436,130 @@ class ForexDataState extends State<ForexData> {
|
||||
isDesktop: widget.isDesktop,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
width: double.infinity,
|
||||
child: Focus(
|
||||
focusNode: focusNodes["country_codeFocusNode"],
|
||||
onFocusChange: (hasFocus) {
|
||||
setState(() {
|
||||
focusStates["country_codeFocused"] = hasFocus;
|
||||
});
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Request focus when user taps
|
||||
focusNodes["country_codeFocusNode"]?.requestFocus();
|
||||
},
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: countryMap[selectedCountry],
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true, // Enables search functionality
|
||||
menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder:
|
||||
(context, item, isSelected) {
|
||||
print("contryItem - $item");
|
||||
final match = RegExp(r'^(.*)\s\((.*)\)$',).firstMatch(item);
|
||||
final countryName = match?.group(1) ?? '';
|
||||
final countryCode = match?.group(2) ?? '';
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 0.02,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
countryName,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
),
|
||||
Text(
|
||||
countryCode,
|
||||
style: GoogleFonts.poppins(fontSize: 11.5,color:Colors.grey),
|
||||
),
|
||||
],
|
||||
width: double.infinity,
|
||||
child: Focus(
|
||||
focusNode: focusNodes["country_codeFocusNode"],
|
||||
onFocusChange: (hasFocus) {
|
||||
setState(() {
|
||||
focusStates["country_codeFocused"] = hasFocus;
|
||||
});
|
||||
},
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
// Request focus when user taps
|
||||
focusNodes["country_codeFocusNode"]?.requestFocus();
|
||||
},
|
||||
child: DropdownSearch<String>(
|
||||
selectedItem: countryMap[selectedCountry],
|
||||
popupProps: PopupProps.menu(
|
||||
showSearchBox: true, // Enables search functionality
|
||||
menuProps: const MenuProps(
|
||||
backgroundColor: Colors.white,
|
||||
),
|
||||
constraints: BoxConstraints(maxHeight: 200),
|
||||
itemBuilder: (context, item, isSelected) {
|
||||
print("contryItem - $item");
|
||||
final match = RegExp(
|
||||
r'^(.*)\s\((.*)\)$',
|
||||
).firstMatch(item);
|
||||
final countryName = match?.group(1) ?? '';
|
||||
final countryCode = match?.group(2) ?? '';
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 8.0,
|
||||
vertical: 0.02,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
countryName,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
);},
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 3,vertical: 3),
|
||||
Text(
|
||||
countryCode,
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11.5,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
items: countryMap.values.toList(),
|
||||
filterFn: (item, filter) {
|
||||
final lowerFilter = filter.toLowerCase();
|
||||
|
||||
final match = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(item);
|
||||
final countryName = match?.group(1)?.toLowerCase() ?? '';
|
||||
final countryCode = match?.group(2)?.toLowerCase() ?? '';
|
||||
|
||||
// Prioritize country code match, fallback to country name
|
||||
return countryCode.contains(lowerFilter) || countryName.contains(lowerFilter);
|
||||
},
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ?? false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
// width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
vertical: 8.0,),
|
||||
);
|
||||
},
|
||||
searchFieldProps: TextFieldProps(
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search ...",
|
||||
hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 3,
|
||||
vertical: 3,
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
),
|
||||
),
|
||||
items: countryMap.values.toList(),
|
||||
filterFn: (item, filter) {
|
||||
final lowerFilter = filter.toLowerCase();
|
||||
|
||||
final match = RegExp(
|
||||
r'^(.*)\s\((.*)\)$',
|
||||
).firstMatch(item);
|
||||
final countryName =
|
||||
match?.group(1)?.toLowerCase() ?? '';
|
||||
final countryCode =
|
||||
match?.group(2)?.toLowerCase() ?? '';
|
||||
|
||||
// Prioritize country code match, fallback to country name
|
||||
return countryCode.contains(lowerFilter) ||
|
||||
countryName.contains(lowerFilter);
|
||||
},
|
||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
dropdownSearchDecoration: InputDecoration(
|
||||
// border: InputBorder.none,
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// width: 0.5,
|
||||
),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color:
|
||||
(focusStates["country_codeFocused"] ??
|
||||
false)
|
||||
? widget.layoutColor!
|
||||
: Colors.white,
|
||||
// : const Color(0xFFD6D5E6),
|
||||
// width: 0.5,
|
||||
// const Color(0xFFD6D5E6),
|
||||
),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: widget.layoutColor!,
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(
|
||||
horizontal: 10.0,
|
||||
vertical: 8.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
dropdownBuilder:
|
||||
(context, selectedItem) => Align(
|
||||
// Center-align selected item
|
||||
alignment: Alignment.centerLeft,
|
||||
child: Text(
|
||||
@ -541,100 +567,105 @@ class ForexDataState extends State<ForexData> {
|
||||
style: GoogleFonts.poppins(fontSize: 11),
|
||||
),
|
||||
),
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedCountry =
|
||||
countryMap.entries
|
||||
.firstWhere((entry) => entry.value == newValue)
|
||||
.key;
|
||||
final setMatch = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(newValue!);
|
||||
final setCountryName = setMatch?.group(1)?.toLowerCase() ?? '';
|
||||
selectedCountryName = setCountryName;
|
||||
setCurrencyFromSelectedCountry(selectedCountry!);
|
||||
});
|
||||
},
|
||||
),
|
||||
// child: DropdownSearch<String>(
|
||||
// selectedItem: countryMap[selectedCountry],
|
||||
// popupProps: PopupProps.menu(
|
||||
// showSearchBox: true, // Enables search functionality
|
||||
// menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
// constraints: BoxConstraints(maxHeight: 250),
|
||||
// itemBuilder:
|
||||
// (context, item, isSelected) => Padding(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 10.0,
|
||||
// vertical: 8.0,
|
||||
// ),
|
||||
// child: Text(
|
||||
// item,
|
||||
// style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
// ),
|
||||
// ),
|
||||
// searchFieldProps: TextFieldProps(
|
||||
// decoration: InputDecoration(
|
||||
// hintText: "Search ...",
|
||||
// hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// items: countryMap.values.toList(),
|
||||
// dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
// dropdownSearchDecoration: InputDecoration(
|
||||
// // border: InputBorder.none,
|
||||
// border: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// borderSide: BorderSide(
|
||||
// color:
|
||||
// (focusStates["country_codeFocused"] ?? false)
|
||||
// ? widget.layoutColor!
|
||||
// : Colors.white,
|
||||
// // width: 0.5,
|
||||
// ),
|
||||
// ),
|
||||
// enabledBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(
|
||||
// color:
|
||||
// (focusStates["country_codeFocused"] ?? false)
|
||||
// ? widget.layoutColor!
|
||||
// : Colors.white,
|
||||
// // : const Color(0xFFD6D5E6),
|
||||
// // width: 0.5,
|
||||
// // const Color(0xFFD6D5E6),
|
||||
// ),
|
||||
// ),
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
// ),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
// vertical: 8.0,),
|
||||
// ),
|
||||
// ),
|
||||
// dropdownBuilder:
|
||||
// (context, selectedItem) => Align(
|
||||
// // Center-align selected item
|
||||
// alignment: Alignment.centerLeft,
|
||||
// child: Text(
|
||||
// selectedItem ?? "Select ",
|
||||
// style: GoogleFonts.poppins(fontSize: 11),
|
||||
// ),
|
||||
// ),
|
||||
// onChanged: (String? newValue) {
|
||||
// setState(() {
|
||||
// // Find the country_code based on selected country_name
|
||||
// selectedCountry =
|
||||
// countryMap.entries
|
||||
// .firstWhere((entry) => entry.value == newValue)
|
||||
// .key;
|
||||
// selectedCountryName = newValue;
|
||||
// setCurrencyFromSelectedCountry(selectedCountry!);
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
)
|
||||
)
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
// Find the country_code based on selected country_name
|
||||
selectedCountry =
|
||||
countryMap.entries
|
||||
.firstWhere(
|
||||
(entry) => entry.value == newValue,
|
||||
)
|
||||
.key;
|
||||
final setMatch = RegExp(
|
||||
r'^(.*)\s\((.*)\)$',
|
||||
).firstMatch(newValue!);
|
||||
final setCountryName =
|
||||
setMatch?.group(1)?.toLowerCase() ?? '';
|
||||
selectedCountryName = setCountryName;
|
||||
setCurrencyFromSelectedCountry(selectedCountry!);
|
||||
});
|
||||
},
|
||||
),
|
||||
// child: DropdownSearch<String>(
|
||||
// selectedItem: countryMap[selectedCountry],
|
||||
// popupProps: PopupProps.menu(
|
||||
// showSearchBox: true, // Enables search functionality
|
||||
// menuProps: const MenuProps(backgroundColor: Colors.white),
|
||||
// constraints: BoxConstraints(maxHeight: 250),
|
||||
// itemBuilder:
|
||||
// (context, item, isSelected) => Padding(
|
||||
// padding: const EdgeInsets.symmetric(
|
||||
// horizontal: 10.0,
|
||||
// vertical: 8.0,
|
||||
// ),
|
||||
// child: Text(
|
||||
// item,
|
||||
// style: GoogleFonts.poppins(fontSize: 11.5),
|
||||
// ),
|
||||
// ),
|
||||
// searchFieldProps: TextFieldProps(
|
||||
// decoration: InputDecoration(
|
||||
// hintText: "Search ...",
|
||||
// hintStyle: GoogleFonts.poppins(fontSize: 11),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 4),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// items: countryMap.values.toList(),
|
||||
// dropdownDecoratorProps: DropDownDecoratorProps(
|
||||
// dropdownSearchDecoration: InputDecoration(
|
||||
// // border: InputBorder.none,
|
||||
// border: OutlineInputBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// borderSide: BorderSide(
|
||||
// color:
|
||||
// (focusStates["country_codeFocused"] ?? false)
|
||||
// ? widget.layoutColor!
|
||||
// : Colors.white,
|
||||
// // width: 0.5,
|
||||
// ),
|
||||
// ),
|
||||
// enabledBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(
|
||||
// color:
|
||||
// (focusStates["country_codeFocused"] ?? false)
|
||||
// ? widget.layoutColor!
|
||||
// : Colors.white,
|
||||
// // : const Color(0xFFD6D5E6),
|
||||
// // width: 0.5,
|
||||
// // const Color(0xFFD6D5E6),
|
||||
// ),
|
||||
// ),
|
||||
// focusedBorder: OutlineInputBorder(
|
||||
// borderSide: BorderSide(color: widget.layoutColor!, width: 1),
|
||||
// ),
|
||||
// contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
|
||||
// vertical: 8.0,),
|
||||
// ),
|
||||
// ),
|
||||
// dropdownBuilder:
|
||||
// (context, selectedItem) => Align(
|
||||
// // Center-align selected item
|
||||
// alignment: Alignment.centerLeft,
|
||||
// child: Text(
|
||||
// selectedItem ?? "Select ",
|
||||
// style: GoogleFonts.poppins(fontSize: 11),
|
||||
// ),
|
||||
// ),
|
||||
// onChanged: (String? newValue) {
|
||||
// setState(() {
|
||||
// // Find the country_code based on selected country_name
|
||||
// selectedCountry =
|
||||
// countryMap.entries
|
||||
// .firstWhere((entry) => entry.value == newValue)
|
||||
// .key;
|
||||
// selectedCountryName = newValue;
|
||||
// setCurrencyFromSelectedCountry(selectedCountry!);
|
||||
// });
|
||||
// },
|
||||
// ),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["country_code"] != null) ...[
|
||||
@ -913,22 +944,23 @@ class ForexDataState extends State<ForexData> {
|
||||
// // You can get text from commentController.text
|
||||
// // Navigator.of(context).pop(); // Close the modal
|
||||
// },
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -168,6 +168,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -193,6 +194,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -368,9 +370,10 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
return input
|
||||
.toLowerCase()
|
||||
.split(' ')
|
||||
.map((word) => word.isNotEmpty
|
||||
? word[0].toUpperCase() + word.substring(1)
|
||||
: '')
|
||||
.map(
|
||||
(word) =>
|
||||
word.isNotEmpty ? word[0].toUpperCase() + word.substring(1) : '',
|
||||
)
|
||||
.join(' ');
|
||||
}
|
||||
|
||||
@ -464,15 +467,13 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Perdiem Amount Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Perdiem Amount Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -488,8 +489,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.1),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -634,7 +635,7 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
future: futureForex,
|
||||
builder: (context, snapshot) {
|
||||
if (futureForex == null) {
|
||||
return const CircularProgressIndicator();
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@ -790,7 +791,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
),
|
||||
DataCell(
|
||||
Text(
|
||||
toTitleCase(forex['country_name']) ?? '',
|
||||
toTitleCase(forex['country_name']) ??
|
||||
'',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
@ -921,7 +923,8 @@ class ForexDataListState extends State<ForexDataList> {
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
toTitleCase(forex['country_name']) ?? 'N/A',
|
||||
toTitleCase(forex['country_name']) ??
|
||||
'N/A',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
|
||||
@ -824,6 +824,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -964,6 +965,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1010,6 +1012,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1081,6 +1084,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1139,6 +1143,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1289,6 +1294,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(data),
|
||||
);
|
||||
@ -1500,6 +1506,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
|
||||
@ -300,6 +300,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -332,6 +333,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
@ -446,6 +448,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -595,6 +595,7 @@ class _PolicyState extends State<Policy> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(policyData), // Convert map to JSON
|
||||
);
|
||||
|
||||
@ -139,10 +139,12 @@ class _PolicyListState extends State<PolicyList> {
|
||||
filteredPolicy =
|
||||
allPolicy.where((object) {
|
||||
final isActiveStatus =
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['policy_id']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['policy_id']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['name']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(object['policy_type']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(object['policy_type']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
}).toList();
|
||||
currentPage = 0;
|
||||
@ -185,6 +187,7 @@ class _PolicyListState extends State<PolicyList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(policyData), // Convert map to JSON
|
||||
);
|
||||
@ -339,15 +342,13 @@ class _PolicyListState extends State<PolicyList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Policy',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Policy'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -363,8 +364,8 @@ class _PolicyListState extends State<PolicyList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.145),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.28),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.28),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -1029,32 +1030,34 @@ class _PolicyListState extends State<PolicyList> {
|
||||
children: [
|
||||
Expanded(
|
||||
child:
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty && filteredPolicy.isEmpty
|
||||
? Center(
|
||||
child: Text( "No Matches Found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
)
|
||||
)
|
||||
: (searchController.text.isNotEmpty && filteredPolicy.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
isDesktop
|
||||
? (searchController.text.isNotEmpty &&
|
||||
filteredPolicy.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No Matches Found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedUser)
|
||||
),
|
||||
),
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
))
|
||||
: (searchController.text.isNotEmpty &&
|
||||
filteredPolicy.isEmpty
|
||||
? Center(
|
||||
child: Text(
|
||||
"No Matches Found",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 14,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)
|
||||
: buildMobileCardView(paginatedUser)),
|
||||
),
|
||||
PaginationControls(
|
||||
currentPage: currentPage,
|
||||
|
||||
@ -105,6 +105,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -168,7 +169,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postPurposeOfTravelData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -212,6 +213,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(purposeOfTravelData);
|
||||
|
||||
@ -429,22 +431,23 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
|
||||
// ),
|
||||
SizedBox(
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -132,7 +132,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
}
|
||||
|
||||
Future<List<dynamic>> fetchGetPurposeOfTravel() async {
|
||||
final String apiUrlData = '$apiUrl/api/getPurposeOfTravelList?for=table_view';
|
||||
final String apiUrlData =
|
||||
'$apiUrl/api/getPurposeOfTravelList?for=table_view';
|
||||
|
||||
final String? token = await getToken();
|
||||
|
||||
@ -148,6 +149,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
print("called api : $apiUrlData");
|
||||
@ -180,11 +182,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
allPurposeOfTravel.where((object) {
|
||||
final isActiveStatus =
|
||||
object['is_active'] == "1" ? "active" : "inactive";
|
||||
return (object['id']?.toLowerCase().contains(
|
||||
lowerQuery,
|
||||
) ??
|
||||
return (object['id']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ??
|
||||
false) ||
|
||||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
// (object['description']?.toLowerCase().contains(lowerQuery) ??
|
||||
// false) ||
|
||||
(isActiveStatus.contains(lowerQuery));
|
||||
@ -284,15 +285,13 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Purpose Of Travel Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Purpose Of Travel Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -308,8 +307,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.08),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -583,10 +582,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
rows:
|
||||
paginatedPurposeOfTravel.map((tableObject) {
|
||||
String purposeOfTravelId =
|
||||
tableObject['id']
|
||||
.toString(); // Get user ID
|
||||
tableObject['id'].toString(); // Get user ID
|
||||
bool isSelected =
|
||||
selectedPurposeOfTravelId == purposeOfTravelId;
|
||||
selectedPurposeOfTravelId ==
|
||||
purposeOfTravelId;
|
||||
|
||||
return DataRow(
|
||||
cells: [
|
||||
@ -635,7 +634,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
// ),
|
||||
GestureDetector(
|
||||
child: Tooltip(
|
||||
message: 'Edit Purpose Of Travel Details',
|
||||
message:
|
||||
'Edit Purpose Of Travel Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
@ -646,10 +646,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
// final userId = getUserId(user['user_id']);
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final purposeOfTravelId = int.tryParse(
|
||||
tableObject['id']
|
||||
.toString(),
|
||||
);
|
||||
final purposeOfTravelId =
|
||||
int.tryParse(
|
||||
tableObject['id'].toString(),
|
||||
);
|
||||
|
||||
if (purposeOfTravelId != null) {
|
||||
print(
|
||||
@ -664,7 +664,9 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => PurposeOfTravelData(
|
||||
(
|
||||
context,
|
||||
) => PurposeOfTravelData(
|
||||
isDesktop: isDesktop,
|
||||
purposeOfTravelId:
|
||||
purposeOfTravelId, // Pass the ID
|
||||
@ -728,7 +730,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
|
||||
GestureDetector(
|
||||
child: Tooltip(
|
||||
message: 'Edit Purpose Of Travel Details',
|
||||
message:
|
||||
'Edit Purpose Of Travel Details',
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
@ -740,8 +743,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
// final usersData = await getUserDetails(userId);
|
||||
//
|
||||
final purposeOfTravelId = int.tryParse(
|
||||
cardObject['id']
|
||||
.toString(),
|
||||
cardObject['id'].toString(),
|
||||
);
|
||||
|
||||
if (purposeOfTravelId != null) {
|
||||
@ -757,7 +759,9 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder:
|
||||
(context) => PurposeOfTravelData(
|
||||
(
|
||||
context,
|
||||
) => PurposeOfTravelData(
|
||||
isDesktop: isDesktop,
|
||||
purposeOfTravelId:
|
||||
purposeOfTravelId, // Pass the ID
|
||||
|
||||
@ -106,6 +106,7 @@ class TravellerDataState extends State<TravellerData> {
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _addFocusListener(FocusNode node, Function(bool) updateState) {
|
||||
node.addListener(() {
|
||||
setState(() {
|
||||
@ -188,7 +189,7 @@ class TravellerDataState extends State<TravellerData> {
|
||||
// This triggers UI rebuild with error messages
|
||||
if (validateData()) {
|
||||
postTravellerData();
|
||||
}else{
|
||||
} else {
|
||||
isDisable = false;
|
||||
}
|
||||
});
|
||||
@ -235,6 +236,7 @@ class TravellerDataState extends State<TravellerData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode(travellerData);
|
||||
|
||||
@ -550,22 +552,23 @@ class TravellerDataState extends State<TravellerData> {
|
||||
// ),
|
||||
SizedBox(
|
||||
child: ElevatedButton(
|
||||
onPressed: isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
onPressed:
|
||||
isDisable
|
||||
? null
|
||||
: () async {
|
||||
setState(() {
|
||||
isDisable = true;
|
||||
});
|
||||
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
await handleSubmit();
|
||||
// You can get text from commentController.text
|
||||
// Navigator.of(context).pop(); // Close the modal
|
||||
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
// Optional: re-enable only on error
|
||||
// setState(() {
|
||||
// isDisable = false;
|
||||
// });
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColor,
|
||||
shape: RoundedRectangleBorder(
|
||||
|
||||
@ -151,6 +151,7 @@ class TravellerListState extends State<TravellerList> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
print("called api : $apiUrlData");
|
||||
@ -294,15 +295,13 @@ class TravellerListState extends State<TravellerList> {
|
||||
isDesktop: isDesktop,
|
||||
breadcrumbItems: [
|
||||
BreadcrumbItem(
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
}
|
||||
),
|
||||
BreadcrumbItem(
|
||||
title: 'Traveller Details',
|
||||
title: 'Org Settings',
|
||||
tooltip: 'Go To Organization Settings',
|
||||
onTap: (context) {
|
||||
context.go("/OrganizationSettings");
|
||||
},
|
||||
),
|
||||
BreadcrumbItem(title: 'Traveller Details'),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -318,8 +317,8 @@ class TravellerListState extends State<TravellerList> {
|
||||
),
|
||||
if (isDesktop)
|
||||
SizedBox(width: MediaQuery.of(context).size.width * 0.10),
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
|
||||
// SizedBox(width: MediaQuery.of(context).size.width * 0.16),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
@ -466,7 +465,7 @@ class TravellerListState extends State<TravellerList> {
|
||||
builder: (context, snapshot) {
|
||||
final adjHgt = MediaQuery.of(context).size.height;
|
||||
if (futureTraveller == null) {
|
||||
return CircularProgressIndicator();
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
}
|
||||
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
|
||||
@ -990,6 +990,7 @@ class _CreateTravelAgentFormDetialsState
|
||||
// Use MultipartRequest (POST only)
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
if (isUpdating) {
|
||||
|
||||
@ -12,43 +12,35 @@ import '../../../services/apiService.dart';
|
||||
import '../../../utils/auth_utils.dart';
|
||||
import '../../../widgets/custom_user_form.dart';
|
||||
|
||||
|
||||
class ChangePasswordDialogData extends StatefulWidget {
|
||||
|
||||
final dynamic isDesktop;
|
||||
final dynamic layoutColor;
|
||||
final dynamic updaterUserId;
|
||||
final dynamic updaterEmail;
|
||||
|
||||
const ChangePasswordDialogData({
|
||||
super.key,
|
||||
this.isDesktop,
|
||||
this.layoutColor,
|
||||
this.updaterUserId,
|
||||
this.updaterEmail
|
||||
super.key,
|
||||
this.isDesktop,
|
||||
this.layoutColor,
|
||||
this.updaterUserId,
|
||||
this.updaterEmail,
|
||||
});
|
||||
|
||||
|
||||
@override
|
||||
ChangePasswordDialogDataState createState() => ChangePasswordDialogDataState();
|
||||
}
|
||||
@override
|
||||
ChangePasswordDialogDataState createState() =>
|
||||
ChangePasswordDialogDataState();
|
||||
}
|
||||
|
||||
class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
final Map<String, TextEditingController> controllers = {};
|
||||
Map<String, String> errorMessages = {};
|
||||
|
||||
|
||||
String? loggeduserId;
|
||||
String? updaterUserIdForAPI;
|
||||
|
||||
List<String> dataHeader = [
|
||||
"email",
|
||||
"changePassword",
|
||||
"confirmPassword"
|
||||
];
|
||||
List<String> dataHeader = ["email", "changePassword", "confirmPassword"];
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
@ -75,15 +67,13 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
}
|
||||
|
||||
setState(() {
|
||||
controllers['email']?.text = widget.updaterEmail ;
|
||||
controllers['email']?.text = widget.updaterEmail;
|
||||
controllers['changePassword']?.text = '';
|
||||
controllers['confirmPassword']?.text = '';
|
||||
updaterUserIdForAPI = widget.updaterUserId;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
void _clearError() {
|
||||
setState(() {
|
||||
errorMessages.clear();
|
||||
@ -98,40 +88,37 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool validateData() {
|
||||
errorMessages.clear();
|
||||
|
||||
final String? email = controllers["email"]?.text;
|
||||
final String? changePassword = controllers["changePassword"]?.text;
|
||||
final String? confirmPassword = controllers["confirmPassword"]?.text;
|
||||
final String? email = controllers["email"]?.text;
|
||||
final String? changePassword = controllers["changePassword"]?.text;
|
||||
final String? confirmPassword = controllers["confirmPassword"]?.text;
|
||||
|
||||
// Required fields check
|
||||
if (email == null || email.trim().isEmpty) {
|
||||
errorMessages["email"] = "Required";
|
||||
}
|
||||
|
||||
if (changePassword == null || changePassword.trim().isEmpty) {
|
||||
errorMessages["changePassword"] = "Required";
|
||||
}
|
||||
|
||||
if (confirmPassword == null || confirmPassword.trim().isEmpty) {
|
||||
errorMessages["confirmPassword"] = "Required";
|
||||
}
|
||||
|
||||
// Password match check
|
||||
if ((changePassword?.isNotEmpty ?? false) &&
|
||||
(confirmPassword?.isNotEmpty ?? false) &&
|
||||
changePassword != confirmPassword) {
|
||||
errorMessages["changePassword"] = "Passwords do not match";
|
||||
errorMessages["confirmPassword"] = "Passwords do not match";
|
||||
}
|
||||
|
||||
// setState(() {}); // Update UI with any error messages
|
||||
return errorMessages.isEmpty;
|
||||
// Required fields check
|
||||
if (email == null || email.trim().isEmpty) {
|
||||
errorMessages["email"] = "Required";
|
||||
}
|
||||
|
||||
if (changePassword == null || changePassword.trim().isEmpty) {
|
||||
errorMessages["changePassword"] = "Required";
|
||||
}
|
||||
|
||||
if (confirmPassword == null || confirmPassword.trim().isEmpty) {
|
||||
errorMessages["confirmPassword"] = "Required";
|
||||
}
|
||||
|
||||
// Password match check
|
||||
if ((changePassword?.isNotEmpty ?? false) &&
|
||||
(confirmPassword?.isNotEmpty ?? false) &&
|
||||
changePassword != confirmPassword) {
|
||||
errorMessages["changePassword"] = "Passwords do not match";
|
||||
errorMessages["confirmPassword"] = "Passwords do not match";
|
||||
}
|
||||
|
||||
// setState(() {}); // Update UI with any error messages
|
||||
return errorMessages.isEmpty;
|
||||
}
|
||||
|
||||
Future<void> handleSubmit() async {
|
||||
loggeduserId = await getUserId();
|
||||
@ -142,7 +129,6 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
postData();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
Future<void> postData() async {
|
||||
@ -152,12 +138,14 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
|
||||
final password = controllers["changePassword"]?.text ?? '';
|
||||
final confirmPassword = controllers["confirmPassword"]?.text ?? '';
|
||||
final String apiUrldata = '$apiUrl/api/user/user-password/$updaterUserIdForAPI';
|
||||
final String apiUrldata =
|
||||
'$apiUrl/api/user/user-password/$updaterUserIdForAPI';
|
||||
|
||||
final token = await getToken();
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
|
||||
try {
|
||||
@ -165,6 +153,7 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
final headers = {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
};
|
||||
final body = jsonEncode({
|
||||
"password": password,
|
||||
@ -200,7 +189,6 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
return AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30),
|
||||
@ -220,10 +208,7 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Divider(
|
||||
thickness: 0.2,
|
||||
color: Colors.blueGrey.shade100,
|
||||
),
|
||||
Divider(thickness: 0.2, color: Colors.blueGrey.shade100),
|
||||
const SizedBox(height: 5),
|
||||
|
||||
Column(
|
||||
@ -232,9 +217,10 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
Text(
|
||||
"Email",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
@ -245,18 +231,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
// ? MediaQuery.of(context).size.width * 0.330
|
||||
// : MediaQuery.of(context).size.width * 0.66,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["email"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Email",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
)),
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["email"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Email",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["email"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
@ -267,18 +254,17 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Change Password",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
@ -286,18 +272,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
isDesktop: widget.isDesktop,
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["changePassword"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Change Password",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
)),
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["changePassword"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Change Password",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["changePassword"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
@ -308,18 +295,17 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
SizedBox(height: 15),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Confirm Password",
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74)),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF575A74),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
CustomTextFieldUserWrapper(
|
||||
@ -327,18 +313,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
isDesktop: widget.isDesktop,
|
||||
color: Colors.transparent,
|
||||
child: SizedBox(
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["confirmPassword"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Confirm Password",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
)),
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: controllers["confirmPassword"],
|
||||
style: const TextStyle(fontSize: 12),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "Confirm Password",
|
||||
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
|
||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||
border: InputBorder.none,
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (errorMessages["confirmPassword"] != null) ...[
|
||||
SizedBox(height: 5), // Space before error message
|
||||
@ -349,10 +336,8 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
],
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
|
||||
SizedBox(height: 15),
|
||||
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
@ -367,17 +352,20 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
child: Text('Save',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11, color: Colors.white)),
|
||||
child: Text(
|
||||
'Save',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 11,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
),
|
||||
// : SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1259,6 +1259,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
|
||||
// Use MultipartRequest (POST only)
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
if (isUpdating) {
|
||||
|
||||
@ -161,6 +161,7 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -186,6 +187,7 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -587,6 +589,9 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
// Attach the file to the request
|
||||
// Set authorization token in headers
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] =
|
||||
'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// request.files.add(http.MultipartFile.fromBytes('file', fileBytes, filename: fileName));
|
||||
|
||||
request.files.add(
|
||||
@ -718,6 +723,7 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
// Use MultipartRequest (POST only)
|
||||
final request = http.MultipartRequest('POST', uri);
|
||||
request.headers['Authorization'] = 'Bearer $token';
|
||||
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
|
||||
|
||||
// If updating, spoof the method Laravel-style
|
||||
|
||||
|
||||
@ -34,8 +34,8 @@ class _MyAppState extends State<MyApp> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
SemanticsBinding.instance
|
||||
.ensureSemantics(); // -only for testing uncomment, Otherwise Email Template wont allow to type
|
||||
// SemanticsBinding.instance
|
||||
// .ensureSemantics(); // -only for testing uncomment, Otherwise Email Template wont allow to type
|
||||
if (kIsWeb) {
|
||||
final uri = Uri.parse(html.window.location.href);
|
||||
print("URI - $uri");
|
||||
@ -87,7 +87,7 @@ class _MyAppState extends State<MyApp> {
|
||||
print("handleTokenUsingMS- $authCode");
|
||||
try {
|
||||
// final url = 'http://localhost:43627/tstat/auth/verifyMSAuthUser?code=$authCode';
|
||||
final url = '$apiUrl/auth/verifyMSAuthUser?code=$authCode';
|
||||
final url = '$apiUrl/api/auth/verifyMSAuthUser?code=$authCode';
|
||||
print("Microsoft BE URL - $url");
|
||||
final response = await http.get(
|
||||
Uri.parse(url),
|
||||
|
||||
@ -44,6 +44,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -80,6 +81,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -116,6 +118,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -156,6 +159,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -185,6 +189,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -240,6 +245,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -291,6 +297,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -330,6 +337,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -367,6 +375,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -404,6 +413,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -441,6 +451,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -476,6 +487,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -518,6 +530,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -559,6 +572,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -583,6 +597,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -664,6 +679,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -710,6 +726,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
// 'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -747,6 +764,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
// 'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -786,6 +804,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
// 'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -850,6 +869,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
// 'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -915,6 +935,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
// 'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -965,6 +986,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1010,6 +1032,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1054,6 +1077,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1100,6 +1124,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1146,6 +1171,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1200,6 +1226,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1346,6 +1373,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1392,6 +1420,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1438,6 +1467,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1480,6 +1510,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -1534,6 +1565,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
if (response.statusCode == 200) {
|
||||
@ -1573,6 +1605,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: body,
|
||||
);
|
||||
@ -1616,6 +1649,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: body,
|
||||
);
|
||||
@ -1673,6 +1707,7 @@ class ApiService {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@ -122,6 +122,7 @@ class CommentModalState extends State<CommentModal> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
);
|
||||
|
||||
@ -143,7 +144,8 @@ class CommentModalState extends State<CommentModal> {
|
||||
print("Res1 - $data");
|
||||
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||
throw Exception(
|
||||
"Invalid response format: 'data' field is missing or not a Map");
|
||||
"Invalid response format: 'data' field is missing or not a Map",
|
||||
);
|
||||
}
|
||||
return data['data'];
|
||||
} else {
|
||||
@ -186,6 +188,7 @@ class CommentModalState extends State<CommentModal> {
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
'app-signature': 'ts-traveltool-2025-signature-123456',
|
||||
},
|
||||
body: jsonEncode(remarksData), // Convert map to JSON
|
||||
);
|
||||
@ -255,7 +258,8 @@ class CommentModalState extends State<CommentModal> {
|
||||
icon: const Icon(Icons.delete, size: 20),
|
||||
onPressed: () async {
|
||||
await postRemarksData(
|
||||
isActive: 0); // Marks the remark as deleted
|
||||
isActive: 0,
|
||||
); // Marks the remark as deleted
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
@ -280,27 +284,30 @@ class CommentModalState extends State<CommentModal> {
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Row 3: OK button
|
||||
|
||||
editRemarks
|
||||
? SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
postRemarksData();
|
||||
// You can get text from commentController.text
|
||||
Navigator.of(context).pop(); // Close the modal
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColorForUser,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: () {
|
||||
postRemarksData();
|
||||
// You can get text from commentController.text
|
||||
Navigator.of(context).pop(); // Close the modal
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: widget.layoutColorForUser,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text('OK',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13, color: Colors.white)),
|
||||
),
|
||||
)
|
||||
child: Text(
|
||||
'OK',
|
||||
style: GoogleFonts.poppins(
|
||||
fontSize: 13,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: SizedBox.shrink(),
|
||||
],
|
||||
),
|
||||
|
||||
@ -609,10 +609,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: mime
|
||||
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
|
||||
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.0"
|
||||
version: "1.0.6"
|
||||
nested:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user