APP-SIGNATURE

This commit is contained in:
venbaittech 2025-08-20 17:45:27 +05:30
parent d29caf66c5
commit f7342a14b4
39 changed files with 1371 additions and 981 deletions

View File

@ -221,6 +221,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -253,6 +254,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(planData), // Convert map to JSON body: jsonEncode(planData), // Convert map to JSON
); );
@ -308,6 +310,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );

View File

@ -29,7 +29,8 @@ class _CommentModalListState extends State<CommentModalList> {
Future<List<Map<String, dynamic>>> fetchComments1() async { Future<List<Map<String, dynamic>>> fetchComments1() async {
final response = await http.get( final response = await http.get(
Uri.parse( Uri.parse(
'$apiUrl/api/plans/getRemarksByPlanId?plan_id=${widget.planId}'), '$apiUrl/api/plans/getRemarksByPlanId?plan_id=${widget.planId}',
),
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
@ -58,6 +59,7 @@ class _CommentModalListState extends State<CommentModalList> {
Uri.parse(apiUrldata), Uri.parse(apiUrldata),
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'app-signature': 'ts-traveltool-2025-signature-123456',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
); );
@ -81,10 +83,7 @@ class _CommentModalListState extends State<CommentModalList> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
title: Text( title: Text('Comments', style: GoogleFonts.poppins(color: Colors.black)),
'Comments',
style: GoogleFonts.poppins(color: Colors.black),
),
content: ConstrainedBox( content: ConstrainedBox(
constraints: const BoxConstraints( constraints: const BoxConstraints(
maxWidth: 500, // You can adjust this width maxWidth: 500, // You can adjust this width
@ -119,64 +118,86 @@ class _CommentModalListState extends State<CommentModalList> {
child: DataTable( child: DataTable(
columns: [ columns: [
DataColumn( DataColumn(
label: Text( label: Text(
'Name', 'Name',
style: style: GoogleFonts.poppins(
GoogleFonts.poppins(fontSize: 11, color: Colors.black), fontSize: 11,
)), color: Colors.black,
),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Comment', 'Comment',
style: style: GoogleFonts.poppins(
GoogleFonts.poppins(fontSize: 11, color: Colors.black), fontSize: 11,
)), color: Colors.black,
),
),
),
DataColumn( DataColumn(
label: Text( label: Text(
'Updated On', 'Updated On',
style: style: GoogleFonts.poppins(
GoogleFonts.poppins(fontSize: 11, color: Colors.black), fontSize: 11,
)), color: Colors.black,
),
),
),
], ],
rows: comments.map((comment) { rows:
final name = comment['created_by_name'] ?? 'Unknown'; comments.map((comment) {
final remark = comment['remarks'] ?? ''; final name = comment['created_by_name'] ?? 'Unknown';
final rawDateStr = comment['updated_on']; final remark = comment['remarks'] ?? '';
String updatedOn = ''; final rawDateStr = comment['updated_on'];
String updatedOn = '';
if (rawDateStr != null && rawDateStr.isNotEmpty) { if (rawDateStr != null && rawDateStr.isNotEmpty) {
try { try {
final parsedDate = DateTime.parse(rawDateStr); final parsedDate = DateTime.parse(rawDateStr);
updatedOn = DateFormat('d MMM yyyy') updatedOn = DateFormat(
.format(parsedDate); // e.g., 15 May 2025 'd MMM yyyy',
} catch (e) { ).format(parsedDate); // e.g., 15 May 2025
updatedOn = rawDateStr.split(' ').first; // fallback } catch (e) {
} updatedOn = rawDateStr.split(' ').first; // fallback
} }
}
return DataRow(cells: [ return DataRow(
DataCell(Text( cells: [
name, DataCell(
style: GoogleFonts.poppins( Text(
fontSize: 12, name,
color: Colors.black, style: GoogleFonts.poppins(
fontWeight: FontWeight.w500), fontSize: 12,
)), color: Colors.black,
DataCell(Text( fontWeight: FontWeight.w500,
remark, ),
style: GoogleFonts.poppins( ),
fontSize: 12, ),
color: Colors.black, DataCell(
fontWeight: FontWeight.w500), Text(
)), remark,
DataCell(Text( style: GoogleFonts.poppins(
updatedOn, fontSize: 12,
style: GoogleFonts.poppins( color: Colors.black,
fontSize: 12, fontWeight: FontWeight.w500,
color: Colors.black, ),
fontWeight: FontWeight.w500), ),
)), ),
]); DataCell(
}).toList(), Text(
updatedOn,
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
fontWeight: FontWeight.w500,
),
),
),
],
);
}).toList(),
), ),
); );
}, },
@ -185,11 +206,14 @@ class _CommentModalListState extends State<CommentModalList> {
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
child: Text('Close', child: Text(
style: GoogleFonts.poppins( 'Close',
fontSize: 12, style: GoogleFonts.poppins(
fontWeight: FontWeight.w500, fontSize: 12,
color: widget.layoutColorForUser)), fontWeight: FontWeight.w500,
color: widget.layoutColorForUser,
),
),
), ),
], ],
); );

View File

@ -211,6 +211,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -243,6 +244,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(planData), // Convert map to JSON body: jsonEncode(planData), // Convert map to JSON
); );

View File

@ -200,6 +200,7 @@ class _ApprovalListState extends State<ApprovalList> {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -233,6 +234,7 @@ class _ApprovalListState extends State<ApprovalList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(planData), // Convert map to JSON body: jsonEncode(planData), // Convert map to JSON
); );
@ -293,6 +295,7 @@ class _ApprovalListState extends State<ApprovalList> {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -525,6 +528,7 @@ class _ApprovalListState extends State<ApprovalList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );

View File

@ -117,6 +117,7 @@ class _LoginWidgetState extends State<LoginWidget> {
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'Accept': 'application/json', 'Accept': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode({ body: jsonEncode({
'email': _emailController.text.trim(), 'email': _emailController.text.trim(),
@ -214,11 +215,14 @@ class _LoginWidgetState extends State<LoginWidget> {
if (_isForgotPassword && !_showOtpResetFields) { if (_isForgotPassword && !_showOtpResetFields) {
print('11'); print('11');
// Step 1: Send OTP // Step 1: Send OTP
final url = '$apiUrl/forgotPassword/verifyUser'; final url = '$apiUrl/api/forgotPassword/verifyUser';
try { try {
final response = await http.post( final response = await http.post(
Uri.parse(url), 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()}), body: jsonEncode({'email': _emailController.text.trim()}),
); );
@ -273,12 +277,15 @@ class _LoginWidgetState extends State<LoginWidget> {
} else if (!_isForgotPassword && _showOtpResetFields) { } else if (!_isForgotPassword && _showOtpResetFields) {
print('22'); print('22');
// Step 2: Verify OTP & Reset Password // Step 2: Verify OTP & Reset Password
final url = '$apiUrl/forgotPassword/changePassword'; final url = '$apiUrl/api/forgotPassword/changePassword';
try { try {
print('21'); print('21');
final response = await http.post( final response = await http.post(
Uri.parse(url), Uri.parse(url),
headers: {'Content-Type': 'application/json'}, headers: {
'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
},
body: jsonEncode({ body: jsonEncode({
'email': _emailController.text.trim(), 'email': _emailController.text.trim(),
'otp': _otpController.text.trim(), 'otp': _otpController.text.trim(),
@ -1111,12 +1118,15 @@ class _LoginWidgetState extends State<LoginWidget> {
} }
Future<void> handleMS() async { Future<void> handleMS() async {
final url = '$apiUrl/auth/mslogin'; final url = '$apiUrl/api/auth/mslogin';
print(url); print(url);
try { try {
final response = await http.get( final response = await http.get(
Uri.parse(url), Uri.parse(url),
headers: {'Content-Type': 'application/json'}, headers: {
'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
},
); );
print("inside try method"); print("inside try method");
if (response.statusCode == 200) { if (response.statusCode == 200) {

View File

@ -105,6 +105,7 @@ class CostCenterDataState extends State<CostCenterData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -168,7 +169,7 @@ class CostCenterDataState extends State<CostCenterData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postCostCenterData(); postCostCenterData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -212,6 +213,7 @@ class CostCenterDataState extends State<CostCenterData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(costcenterData); final body = jsonEncode(costcenterData);
@ -426,22 +428,23 @@ class CostCenterDataState extends State<CostCenterData> {
// ), // ),
SizedBox( SizedBox(
child: ElevatedButton( child: ElevatedButton(
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
// onPressed: () { // onPressed: () {
// handleSubmit(); // handleSubmit();
// // You can get text from commentController.text // // You can get text from commentController.text

View File

@ -149,6 +149,7 @@ class CostCenterListState extends State<CostCenterList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
print("called api : $apiUrlData"); print("called api : $apiUrlData");
@ -286,15 +287,13 @@ class CostCenterListState extends State<CostCenterList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Cost Center Details',
), ),
BreadcrumbItem(title: 'Cost Center Details'),
], ],
), ),
), ),
@ -310,8 +309,8 @@ class CostCenterListState extends State<CostCenterList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.08), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -458,7 +457,7 @@ class CostCenterListState extends State<CostCenterList> {
builder: (context, snapshot) { builder: (context, snapshot) {
final adjHgt = MediaQuery.of(context).size.height; final adjHgt = MediaQuery.of(context).size.height;
if (futureCostCenter == null) { if (futureCostCenter == null) {
return CircularProgressIndicator(); return const Center(child: CircularProgressIndicator());
} }
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {

View File

@ -205,6 +205,7 @@ class StatusDashboardState extends State<StatusDashboard> {
Uri.parse(apiUrlData), Uri.parse(apiUrlData),
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'app-signature': 'ts-traveltool-2025-signature-123456',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
}, },
); );

View File

@ -105,6 +105,7 @@ class DepartmentDataState extends State<DepartmentData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -168,7 +169,7 @@ class DepartmentDataState extends State<DepartmentData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postDepartmentData(); postDepartmentData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -212,6 +213,7 @@ class DepartmentDataState extends State<DepartmentData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(departmentData); final body = jsonEncode(departmentData);
@ -428,22 +430,23 @@ class DepartmentDataState extends State<DepartmentData> {
// ), // ),
SizedBox( SizedBox(
child: ElevatedButton( child: ElevatedButton(
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -149,6 +149,7 @@ class DepartmentListState extends State<DepartmentList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
print("called api : $apiUrlData"); print("called api : $apiUrlData");
@ -181,11 +182,10 @@ class DepartmentListState extends State<DepartmentList> {
allDepartment.where((object) { allDepartment.where((object) {
final isActiveStatus = final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive"; object['is_active'] == "1" ? "active" : "inactive";
return (object['id']?.toLowerCase().contains( return (object['id']?.toLowerCase().contains(lowerQuery) ??
lowerQuery, false) ||
) ?? (object['dropdown_value']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ?? false) ||
// (object['description']?.toLowerCase().contains(lowerQuery) ?? // (object['description']?.toLowerCase().contains(lowerQuery) ??
// false) || // false) ||
(isActiveStatus.contains(lowerQuery)); (isActiveStatus.contains(lowerQuery));
@ -285,15 +285,13 @@ class DepartmentListState extends State<DepartmentList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Department Details',
), ),
BreadcrumbItem(title: 'Department Details'),
], ],
), ),
), ),
@ -309,8 +307,8 @@ class DepartmentListState extends State<DepartmentList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.08), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -584,8 +582,7 @@ class DepartmentListState extends State<DepartmentList> {
rows: rows:
paginatedDepartment.map((tableObject) { paginatedDepartment.map((tableObject) {
String departmentId = String departmentId =
tableObject['id'] tableObject['id'].toString(); // Get user ID
.toString(); // Get user ID
bool isSelected = bool isSelected =
selectedDepartmentId == departmentId; selectedDepartmentId == departmentId;
@ -648,8 +645,7 @@ class DepartmentListState extends State<DepartmentList> {
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final departmentId = int.tryParse( final departmentId = int.tryParse(
tableObject['id'] tableObject['id'].toString(),
.toString(),
); );
if (departmentId != null) { if (departmentId != null) {
@ -741,8 +737,7 @@ class DepartmentListState extends State<DepartmentList> {
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final departmentId = int.tryParse( final departmentId = int.tryParse(
cardObject['id'] cardObject['id'].toString(),
.toString(),
); );
if (departmentId != null) { if (departmentId != null) {

View File

@ -71,6 +71,7 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', '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(); _users = userList.map((user) => SearchUser.fromJson(user)).toList();
_filteredUsers = List.from(_users); _filteredUsers = List.from(_users);
_filterUsers(""); _filterUsers("");
}); });
print("filtered user === ${_filteredUsers.length}"); print("filtered user === ${_filteredUsers.length}");
print("Users fetched: ${_users.length}"); print("Users fetched: ${_users.length}");
@ -132,6 +132,7 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -211,10 +212,15 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
if (query.isEmpty) { if (query.isEmpty) {
// Return all users excluding self and roleId == 5 // Return all users excluding self and roleId == 5
_filteredList = _users.where((user) => _filteredList =
user.userId.toString() != excludedUserId && user.roleId.toString() != "5") _users
.map((user) => {"type": "user", "data": user}) .where(
.toList(); (user) =>
user.userId.toString() != excludedUserId &&
user.roleId.toString() != "5",
)
.map((user) => {"type": "user", "data": user})
.toList();
// _filteredList = [ // _filteredList = [
// // ..._users.map((user) => {"type": "user", "data": user}), // // ..._users.map((user) => {"type": "user", "data": user}),
@ -277,9 +283,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
setState(() { setState(() {
_filteredList.clear(); // Reset the list before filtering _filteredList.clear(); // Reset the list before filtering
if (query.isEmpty) { if (query.isEmpty) {
_filteredList = _traveller _filteredList =
.map((traveller) => {"type": "traveller", "data": traveller}) _traveller
.toList(); .map((traveller) => {"type": "traveller", "data": traveller})
.toList();
// _filteredList = [ // _filteredList = [
// ..._users.map((user) => {"type": "user", "data": user}), // ..._users.map((user) => {"type": "user", "data": user}),
// ]; // ];
@ -377,19 +384,21 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
if (widget.title == "Others (Non Employee)"){ fetchTraveller(); } if (widget.title == "Others (Non Employee)") {
else{ fetchUsers(); } fetchTraveller();
} else {
fetchUsers();
}
print("SelffsdfcurrentUser - ${widget.currentUser}"); print("SelffsdfcurrentUser - ${widget.currentUser}");
_filterByTitle(""); _filterByTitle("");
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isValid =
final isValid = _searchController.text.trim().isNotEmpty && _searchController.text.trim().isNotEmpty &&
userIdSelected.trim().isNotEmpty; userIdSelected.trim().isNotEmpty;
return Dialog( return Dialog(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)),
child: Container( child: Container(
@ -482,81 +491,100 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
// _searchController.text.isNotEmpty // _searchController.text.isNotEmpty
// ? // ?
if (!_showTravellerForm) if (!_showTravellerForm)
SizedBox( SizedBox(
height: 300, // Limit height to avoid overflow height: 300, // Limit height to avoid overflow
// child: _filteredUsers.isEmpty // child: _filteredUsers.isEmpty
child: child:
_filteredList.isEmpty _filteredList.isEmpty
? Center( ? Center(
child: Text( child: Text(
"No users found", "No users found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey, 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 // Traveler Form
if (_showTravellerForm) if (_showTravellerForm)
@ -616,32 +644,35 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
SizedBox(width: 10), SizedBox(width: 10),
ElevatedButton( ElevatedButton(
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: isValid ? widget.layoutColorForUser : Colors.grey, backgroundColor:
isValid ? widget.layoutColorForUser : Colors.grey,
foregroundColor: Colors.white, foregroundColor: Colors.white,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: BorderSide( side: BorderSide(
// color: widget.layoutColorForUser, // color: widget.layoutColorForUser,
color: isValid ? widget.layoutColorForUser : Colors.grey, color:
isValid ? widget.layoutColorForUser : Colors.grey,
width: isValid ? 2 : 0, width: isValid ? 2 : 0,
), ),
), ),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
onPressed: isValid ? () { onPressed:
print("Submitting: ${_searchController.text}, ID: $userIdSelected"); isValid
widget.onSubmit( ? () {
_searchController.text, print(
userIdSelected, "Submitting: ${_searchController.text}, ID: $userIdSelected",
isTraveller, );
); widget.onSubmit(
Navigator.pop(context); _searchController.text,
} userIdSelected,
: null, isTraveller,
child: Text( );
"Save", Navigator.pop(context);
style: GoogleFonts.poppins(fontSize: 11), }
), : null,
child: Text("Save", style: GoogleFonts.poppins(fontSize: 11)),
), ),
], ],
), ),
@ -745,6 +776,7 @@ class _TravelerFormState extends State<TravelerForm> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(requestBody), body: jsonEncode(requestBody),
); );

View File

@ -247,6 +247,7 @@ class _groupState extends State<Group> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(groupData), body: jsonEncode(groupData),
) )
@ -255,6 +256,7 @@ class _groupState extends State<Group> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(groupData), body: jsonEncode(groupData),
)); ));

View File

@ -232,7 +232,7 @@ class GroupDataState extends State<GroupData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postGroupData(); postGroupData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -270,6 +270,7 @@ class GroupDataState extends State<GroupData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(groupData); final body = jsonEncode(groupData);
@ -308,12 +309,12 @@ class GroupDataState extends State<GroupData> {
behavior: SnackBarBehavior.floating, behavior: SnackBarBehavior.floating,
), ),
); );
} } else {
else {
print("Failed to submit plan. Status: ${response.statusCode}"); print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
final message = jsonDecode(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")) { if (errorMessage.contains("Duplicate entry")) {
_clearError(); _clearError();
@ -464,7 +465,11 @@ class GroupDataState extends State<GroupData> {
), ),
), ),
IconButton( 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", tooltip: "Reset",
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -506,15 +511,15 @@ class GroupDataState extends State<GroupData> {
constraints: BoxConstraints(maxHeight: 250), constraints: BoxConstraints(maxHeight: 250),
itemBuilder: itemBuilder:
(context, object, isSelected) => Padding( (context, object, isSelected) => Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8.0, horizontal: 8.0,
vertical: 6.0, vertical: 6.0,
), ),
child: Text( child: Text(
object, object,
style: GoogleFonts.poppins(fontSize: 11.5), style: GoogleFonts.poppins(fontSize: 11.5),
), ),
), ),
searchFieldProps: TextFieldProps( searchFieldProps: TextFieldProps(
decoration: InputDecoration( decoration: InputDecoration(
hintText: "Search ...", hintText: "Search ...",
@ -533,40 +538,47 @@ class GroupDataState extends State<GroupData> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
borderSide: BorderSide( borderSide: BorderSide(
color: color:
(focusStates["domestic_policy_nameFocused"] ?? false) (focusStates["domestic_policy_nameFocused"] ??
? widget.layoutColor! false)
: Colors.white, ? widget.layoutColor!
: Colors.white,
// width: 0.5, // width: 0.5,
), ),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: color:
(focusStates["domestic_policy_nameFocused"] ?? false) (focusStates["domestic_policy_nameFocused"] ??
? widget.layoutColor! false)
: Colors.white, ? widget.layoutColor!
: Colors.white,
// : const Color(0xFFD6D5E6), // : const Color(0xFFD6D5E6),
// width: 0.5, // width: 0.5,
// const Color(0xFFD6D5E6), // const Color(0xFFD6D5E6),
), ),
), ),
focusedBorder: OutlineInputBorder( 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), // contentPadding: EdgeInsets.symmetric(horizontal: 1),
), ),
), ),
dropdownBuilder: dropdownBuilder:
(context, selectedItem) => Align( (context, selectedItem) => Align(
// Center-align selected item // Center-align selected item
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
selectedItem ?? "Select ", selectedItem ?? "Select ",
style: GoogleFonts.poppins(fontSize: 11), style: GoogleFonts.poppins(fontSize: 11),
), ),
), ),
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
// Find the country_code based on selected country_name // Find the country_code based on selected country_name
@ -574,7 +586,7 @@ class GroupDataState extends State<GroupData> {
DomesticMap.entries DomesticMap.entries
.firstWhere( .firstWhere(
(entry) => entry.value == newValue, (entry) => entry.value == newValue,
) )
.key; .key;
selectedDomesticPolicyName = newValue; selectedDomesticPolicyName = newValue;
}); });
@ -602,7 +614,11 @@ class GroupDataState extends State<GroupData> {
), ),
), ),
IconButton( 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", tooltip: "Reset",
onPressed: () { onPressed: () {
setState(() { setState(() {
@ -673,28 +689,35 @@ class GroupDataState extends State<GroupData> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
borderSide: BorderSide( borderSide: BorderSide(
color: color:
(focusStates["international_policy_nameFocused"] ?? false) (focusStates["international_policy_nameFocused"] ??
? widget.layoutColor! false)
: Colors.white, ? widget.layoutColor!
: Colors.white,
width: 0.5, width: 0.5,
), ),
), ),
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(
color: color:
(focusStates["international_policy_nameFocused"] ?? false) (focusStates["international_policy_nameFocused"] ??
? widget.layoutColor! false)
: Colors.white, ? widget.layoutColor!
: Colors.white,
// : const Color(0xFFD6D5E6), // : const Color(0xFFD6D5E6),
width: 0.5, width: 0.5,
// const Color(0xFFD6D5E6), // const Color(0xFFD6D5E6),
), ),
), ),
focusedBorder: OutlineInputBorder( 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), // contentPadding: EdgeInsets.symmetric(horizontal: 1),
), ),
), ),
@ -833,21 +856,22 @@ class GroupDataState extends State<GroupData> {
// // You can get text from commentController.text // // You can get text from commentController.text
// // Navigator.of(context).pop(); // Close the modal // // Navigator.of(context).pop(); // Close the modal
// }, // },
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
await handleSubmit(); });
// You can get text from commentController.text await handleSubmit();
// Navigator.of(context).pop(); // Close the modal // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -190,6 +190,7 @@ class _GroupListState extends State<GroupList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode({ body: jsonEncode({
"is_active": newStatus, // Set new status dynamically "is_active": newStatus, // Set new status dynamically
@ -304,18 +305,17 @@ class _GroupListState extends State<GroupList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Group ',
), ),
BreadcrumbItem(title: 'Group '),
], ],
), ),
), ),
// Text( // Text(
// 'Group', // 'Group',
// style: GoogleFonts.poppins( // style: GoogleFonts.poppins(
@ -324,13 +324,12 @@ class _GroupListState extends State<GroupList> {
// color: Colors.black, // color: Colors.black,
// ), // ),
// ), // ),
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.145), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -625,7 +624,9 @@ class _GroupListState extends State<GroupList> {
// ), // ),
DataCell( DataCell(
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints(maxWidth: 200), // limit description width constraints: BoxConstraints(
maxWidth: 200,
), // limit description width
child: Text( child: Text(
"${group['name'] ?? ''}", "${group['name'] ?? ''}",
style: TextStyle( style: TextStyle(
@ -633,7 +634,8 @@ class _GroupListState extends State<GroupList> {
fontFamily: "Inter", fontFamily: "Inter",
), ),
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
maxLines: 1, // optional: show only 1 line maxLines:
1, // optional: show only 1 line
softWrap: false, softWrap: false,
), ),
), ),
@ -667,7 +669,9 @@ class _GroupListState extends State<GroupList> {
// ), // ),
DataCell( DataCell(
ConstrainedBox( ConstrainedBox(
constraints: BoxConstraints(maxWidth: 200), // limit description width constraints: BoxConstraints(
maxWidth: 200,
), // limit description width
child: Text( child: Text(
"${group['description'] ?? 'N/A'}", "${group['description'] ?? 'N/A'}",
style: TextStyle( style: TextStyle(

View File

@ -120,6 +120,7 @@ class HotelsDataState extends State<HotelsData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -201,7 +202,7 @@ class HotelsDataState extends State<HotelsData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postHotelsData(); postHotelsData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -247,6 +248,7 @@ class HotelsDataState extends State<HotelsData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(hotelsData); final body = jsonEncode(hotelsData);
@ -282,7 +284,6 @@ class HotelsDataState extends State<HotelsData> {
setState(() { setState(() {
isDisable = false; isDisable = false;
}); });
} else { } else {
print("Failed to submit plan. Status: ${response.statusCode}"); print("Failed to submit plan. Status: ${response.statusCode}");
print("Error: ${response.body}"); print("Error: ${response.body}");
@ -291,14 +292,12 @@ class HotelsDataState extends State<HotelsData> {
isDisable = false; isDisable = false;
}); });
} }
} } catch (e) {
catch (e) {
print("Error submitting plan: $e"); print("Error submitting plan: $e");
setState(() { setState(() {
isDisable = false; isDisable = false;
}); });
} }
} }
@override @override
@ -318,7 +317,7 @@ class HotelsDataState extends State<HotelsData> {
countryMap = { countryMap = {
for (var country in countryList) for (var country in countryList)
(country['country_code'] ?? ''): (country['country_code'] ?? ''):
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})', '${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
}; };
// Extract only country codes for processing // Extract only country codes for processing
@ -455,7 +454,9 @@ class HotelsDataState extends State<HotelsData> {
focusNode: focusNodes["categoryFocusNode"], focusNode: focusNodes["categoryFocusNode"],
controller: controllers["category"], controller: controllers["category"],
inputFormatters: [ inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 ]')), FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 ]'),
),
], ],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
@ -489,119 +490,144 @@ class HotelsDataState extends State<HotelsData> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
width: double.infinity, width: double.infinity,
child: Focus( child: Focus(
focusNode: focusNodes["country_codeFocusNode"], focusNode: focusNodes["country_codeFocusNode"],
onFocusChange: (hasFocus) { onFocusChange: (hasFocus) {
setState(() { setState(() {
focusStates["country_codeFocused"] = hasFocus; focusStates["country_codeFocused"] = hasFocus;
}); });
},
child: GestureDetector(
onTap: () {
// Request focus when user taps
focusNodes["country_codeFocusNode"]?.requestFocus();
}, },
child: GestureDetector( child: DropdownSearch<String>(
onTap: () { selectedItem: countryMap[selectedCountry],
// Request focus when user taps popupProps: PopupProps.menu(
focusNodes["country_codeFocusNode"]?.requestFocus(); showSearchBox: true, // Enables search functionality
}, menuProps: const MenuProps(
child: DropdownSearch<String>( backgroundColor: Colors.white,
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;
});
},
), ),
) 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) ...[ if (errorMessages["country_code"] != null) ...[
@ -712,22 +738,23 @@ class HotelsDataState extends State<HotelsData> {
// ), // ),
SizedBox( SizedBox(
child: ElevatedButton( child: ElevatedButton(
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -152,6 +152,7 @@ class HotelsDataListState extends State<HotelsDataList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -177,6 +178,7 @@ class HotelsDataListState extends State<HotelsDataList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -338,15 +340,13 @@ class HotelsDataListState extends State<HotelsDataList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Hotel Details',
), ),
BreadcrumbItem(title: 'Hotel Details'),
], ],
), ),
), ),
@ -508,7 +508,7 @@ class HotelsDataListState extends State<HotelsDataList> {
builder: (context, snapshot) { builder: (context, snapshot) {
final adjHgt = MediaQuery.of(context).size.height; final adjHgt = MediaQuery.of(context).size.height;
if (futureHotels == null) { if (futureHotels == null) {
return CircularProgressIndicator(); return const Center(child: CircularProgressIndicator());
} }
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
@ -892,7 +892,7 @@ class HotelsDataListState extends State<HotelsDataList> {
children: [ children: [
Column( Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"${hotels['category'] ?? ''} ", "${hotels['category'] ?? ''} ",

View File

@ -207,6 +207,7 @@ class _ForexScreenState extends State<ForexScreen> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(forexData), // Convert map to JSON body: jsonEncode(forexData), // Convert map to JSON
); );

View File

@ -1,4 +1,6 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:html' as html;
import 'dart:async';
import 'dart:io' as io show Directory, File; import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart'; import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom; import 'package:flutter/cupertino.dart' as dom;
@ -15,6 +17,9 @@ import 'package:frontend/Screens/myTemplates/templateForex.dart'
as _editorScrollController; as _editorScrollController;
import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller; import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller;
import 'package:html2md/html2md.dart' as html2md; 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:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
import 'package:flutter_quill/flutter_quill.dart' as quill; import 'package:flutter_quill/flutter_quill.dart' as quill;
@ -59,6 +64,8 @@ class TemplateForex extends StatefulWidget {
class TemplateForexState extends State<TemplateForex> { class TemplateForexState extends State<TemplateForex> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
Uint8List? _imageBytes;
String? selectedOrglogo;
// final QuillController _controller = QuillController.basic(); // final QuillController _controller = QuillController.basic();
String? orgId; String? orgId;
String? userId; String? userId;
@ -91,11 +98,6 @@ class TemplateForexState extends State<TemplateForex> {
"body_html": DeltaToHTML.encodeJson( "body_html": DeltaToHTML.encodeJson(
_controller.document.toDelta().toJson(), _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), "placeholder": jsonEncode(placeholderList),
// "created_by": userId // "created_by": userId
}; };
@ -363,7 +365,7 @@ class TemplateForexState extends State<TemplateForex> {
print( print(
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}", "API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}",
); );
setState(() { setState(() async {
// Wrap in setState to update the UI // Wrap in setState to update the UI
controllers["templateName"]?.text = controllers["templateName"]?.text =
widget.templateData?["templateData"]?["template_name"] ?? ""; widget.templateData?["templateData"]?["template_name"] ?? "";
@ -432,7 +434,7 @@ class TemplateForexState extends State<TemplateForex> {
) ?? ) ??
0; 0;
print("Fetched template_id: $templateId"); print("Fetched template_id: $templateId");
fetchSignature();
// if (widget.group?["international_policy_id"] != null) { // if (widget.group?["international_policy_id"] != null) {
// selectedInternational = // selectedInternational =
// widget.group!["international_policy_id"].toString(); // 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 { Future<void> handleSubmit() async {
Map<String, dynamic> data = TemplateData; Map<String, dynamic> data = TemplateData;
@ -492,6 +522,7 @@ class TemplateForexState extends State<TemplateForex> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(policyData), // Convert map to JSON 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ResponsiveBuilder( return ResponsiveBuilder(
@ -683,56 +778,65 @@ class TemplateForexState extends State<TemplateForex> {
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null, width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
child: IconTheme( child: IconTheme(
data: IconThemeData(size: 18), // Set icon size here 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( child: Container(
TextSelection.collapsed( color: Color(0xFFFFFEF0),
offset: _controller.selection.extentOffset + 1, width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
), child: IconTheme(
ChangeSource.local, data: IconThemeData(size: 18), // Set icon size here
); child: QuillSimpleToolbar(controller: _controller),
},
),
],
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: 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( Container(
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -782,9 +886,10 @@ class TemplateForexState extends State<TemplateForex> {
], ],
), ),
), ),
Container( Container(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
height: MediaQuery.of(context).size.height * 0.45, height: MediaQuery.of(context).size.height * 0.38,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
border: Border.all(color: Color(0xFFD6D5E6), width: 0.5), border: Border.all(color: Color(0xFFD6D5E6), width: 0.5),
@ -799,15 +904,16 @@ class TemplateForexState extends State<TemplateForex> {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
embedBuilders: [ embedBuilders: [
...FlutterQuillEmbeds.editorBuilders( ...FlutterQuillEmbeds.editorBuilders(
imageEmbedConfig: QuillEditorImageEmbedConfig( // imageEmbedConfig: QuillEditorImageEmbedConfig(
imageProviderBuilder: (context, imageUrl) { // imageProviderBuilder: (context, imageUrl) {
// https://pub.dev/packages/flutter_quill_extensions#-image-assets // if (imageUrl.startsWith('data:image')) {
if (imageUrl.startsWith('assets/')) { // return MemoryImage(
return AssetImage(imageUrl); // base64Decode(imageUrl.split(',').last),
} // );
return null; // }
}, // return null;
), // },
// ),
videoEmbedConfig: QuillEditorVideoEmbedConfig( videoEmbedConfig: QuillEditorVideoEmbedConfig(
customVideoBuilder: (videoUrl, readOnly) { customVideoBuilder: (videoUrl, readOnly) {
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0 // 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),
),
),
],
),
),
], ],
); );
} }

View File

@ -178,6 +178,7 @@ class TemplatesListState extends State<TemplatesList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -210,6 +211,7 @@ class TemplatesListState extends State<TemplatesList> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
@ -447,24 +449,22 @@ class TemplatesListState extends State<TemplatesList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Templates',
), ),
BreadcrumbItem(title: 'Templates'),
], ],
), ),
), ),
], ],
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.13), 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.23),
if (isDesktop) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -597,7 +597,7 @@ class TemplatesListState extends State<TemplatesList> {
builder: (context, snapshot) { builder: (context, snapshot) {
final adjHgt = MediaQuery.of(context).size.height; final adjHgt = MediaQuery.of(context).size.height;
if (futureTemplates == null) { if (futureTemplates == null) {
return CircularProgressIndicator(); return const Center(child: CircularProgressIndicator());
} }
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());

View File

@ -50,6 +50,7 @@ class _MailSettingState extends State<MailSetting> {
super.dispose(); super.dispose();
} }
Map<String, dynamic> getMailData() => mailData; Map<String, dynamic> getMailData() => mailData;
Map<String, dynamic> get mailData { Map<String, dynamic> get mailData {
@ -169,6 +170,7 @@ class _MailSettingState extends State<MailSetting> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(mailData), // Convert map to JSON 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( Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -447,9 +449,9 @@ class _MailSettingState extends State<MailSetting> {
isFocused: focusStates["senderEmailFocused"] ?? false, isFocused: focusStates["senderEmailFocused"] ?? false,
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
width: width:
widget.isDesktop widget.isDesktop
? MediaQuery.of(context).size.width * 0.23 ? MediaQuery.of(context).size.width * 0.23
: MediaQuery.of(context).size.width * 0.85, : MediaQuery.of(context).size.width * 0.85,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
@ -465,8 +467,7 @@ class _MailSettingState extends State<MailSetting> {
} else if (!RegExp( } else if (!RegExp(
r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$", r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$",
).hasMatch(value)) { ).hasMatch(value)) {
errorMessages["sender_email"] = errorMessages["sender_email"] = "Invalid email format";
"Invalid email format";
} }
}, },
style: GoogleFonts.poppins(fontSize: 12), 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( Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -545,7 +546,7 @@ class _MailSettingState extends State<MailSetting> {
], ],
], ],
), ),
if(isDesktop) SizedBox(width:20), if (isDesktop) SizedBox(width: 20),
Column( Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works mainAxisAlignment: MainAxisAlignment.spaceBetween, // This works
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,

View File

@ -333,6 +333,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {

View File

@ -130,6 +130,7 @@ class ForexDataState extends State<ForexData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -247,7 +248,7 @@ class ForexDataState extends State<ForexData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postForexData(); postForexData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -256,7 +257,6 @@ class ForexDataState extends State<ForexData> {
print("ForexDAta - $forexData1"); print("ForexDAta - $forexData1");
} }
Future<void> postForexData({int isActive = 1}) async { Future<void> postForexData({int isActive = 1}) async {
// final remarksData = getData(); // final remarksData = getData();
@ -296,6 +296,7 @@ class ForexDataState extends State<ForexData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(forexData); final body = jsonEncode(forexData);
@ -375,7 +376,7 @@ class ForexDataState extends State<ForexData> {
countryMap = { countryMap = {
for (var country in countryList) for (var country in countryList)
(country['country_code'] ?? ''): (country['country_code'] ?? ''):
'${country['country_name'] ?? ''} (${country['country_code'] ?? ''})', '${country['country_name'] ?? ''} (${country['country_code'] ?? ''})',
}; };
// Extract only country codes for processing // Extract only country codes for processing
@ -435,105 +436,130 @@ class ForexDataState extends State<ForexData> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
width: double.infinity, width: double.infinity,
child: Focus( child: Focus(
focusNode: focusNodes["country_codeFocusNode"], focusNode: focusNodes["country_codeFocusNode"],
onFocusChange: (hasFocus) { onFocusChange: (hasFocus) {
setState(() { setState(() {
focusStates["country_codeFocused"] = hasFocus; focusStates["country_codeFocused"] = hasFocus;
}); });
}, },
child: GestureDetector( child: GestureDetector(
onTap: () { onTap: () {
// Request focus when user taps // Request focus when user taps
focusNodes["country_codeFocusNode"]?.requestFocus(); focusNodes["country_codeFocusNode"]?.requestFocus();
}, },
child: DropdownSearch<String>( child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry], selectedItem: countryMap[selectedCountry],
popupProps: PopupProps.menu( popupProps: PopupProps.menu(
showSearchBox: true, // Enables search functionality showSearchBox: true, // Enables search functionality
menuProps: const MenuProps(backgroundColor: Colors.white), menuProps: const MenuProps(
constraints: BoxConstraints(maxHeight: 200), backgroundColor: Colors.white,
itemBuilder: ),
(context, item, isSelected) { constraints: BoxConstraints(maxHeight: 200),
print("contryItem - $item"); itemBuilder: (context, item, isSelected) {
final match = RegExp(r'^(.*)\s\((.*)\)$',).firstMatch(item); print("contryItem - $item");
final countryName = match?.group(1) ?? ''; final match = RegExp(
final countryCode = match?.group(2) ?? ''; r'^(.*)\s\((.*)\)$',
return Padding( ).firstMatch(item);
padding: const EdgeInsets.symmetric( final countryName = match?.group(1) ?? '';
horizontal: 8.0, final countryCode = match?.group(2) ?? '';
vertical: 0.02, return Padding(
), padding: const EdgeInsets.symmetric(
child: Padding( horizontal: 8.0,
padding: const EdgeInsets.all(8.0), vertical: 0.02,
child: Row( ),
mainAxisAlignment: MainAxisAlignment.spaceBetween, child: Padding(
children: [ padding: const EdgeInsets.all(8.0),
Text( child: Row(
countryName, mainAxisAlignment:
style: GoogleFonts.poppins(fontSize: 11.5), MainAxisAlignment.spaceBetween,
), children: [
Text( Text(
countryCode, countryName,
style: GoogleFonts.poppins(fontSize: 11.5,color:Colors.grey), style: GoogleFonts.poppins(
), fontSize: 11.5,
], ),
), ),
), Text(
);}, countryCode,
searchFieldProps: TextFieldProps( style: GoogleFonts.poppins(
decoration: InputDecoration( fontSize: 11.5,
hintText: "Search ...", color: Colors.grey,
hintStyle: GoogleFonts.poppins(fontSize: 11), ),
contentPadding: EdgeInsets.symmetric(horizontal: 3,vertical: 3), ),
],
), ),
), ),
), );
items: countryMap.values.toList(), },
filterFn: (item, filter) { searchFieldProps: TextFieldProps(
final lowerFilter = filter.toLowerCase(); decoration: InputDecoration(
hintText: "Search ...",
final match = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(item); hintStyle: GoogleFonts.poppins(fontSize: 11),
final countryName = match?.group(1)?.toLowerCase() ?? ''; contentPadding: EdgeInsets.symmetric(
final countryCode = match?.group(2)?.toLowerCase() ?? ''; horizontal: 3,
vertical: 3,
// 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( ),
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 // Center-align selected item
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
@ -541,100 +567,105 @@ class ForexDataState extends State<ForexData> {
style: GoogleFonts.poppins(fontSize: 11), style: GoogleFonts.poppins(fontSize: 11),
), ),
), ),
onChanged: (String? newValue) { onChanged: (String? newValue) {
setState(() { setState(() {
// Find the country_code based on selected country_name // Find the country_code based on selected country_name
selectedCountry = selectedCountry =
countryMap.entries countryMap.entries
.firstWhere((entry) => entry.value == newValue) .firstWhere(
.key; (entry) => entry.value == newValue,
final setMatch = RegExp(r'^(.*)\s\((.*)\)$').firstMatch(newValue!); )
final setCountryName = setMatch?.group(1)?.toLowerCase() ?? ''; .key;
selectedCountryName = setCountryName; final setMatch = RegExp(
setCurrencyFromSelectedCountry(selectedCountry!); r'^(.*)\s\((.*)\)$',
}); ).firstMatch(newValue!);
}, final setCountryName =
), setMatch?.group(1)?.toLowerCase() ?? '';
// child: DropdownSearch<String>( selectedCountryName = setCountryName;
// selectedItem: countryMap[selectedCountry], setCurrencyFromSelectedCountry(selectedCountry!);
// popupProps: PopupProps.menu( });
// showSearchBox: true, // Enables search functionality },
// menuProps: const MenuProps(backgroundColor: Colors.white), ),
// constraints: BoxConstraints(maxHeight: 250), // child: DropdownSearch<String>(
// itemBuilder: // selectedItem: countryMap[selectedCountry],
// (context, item, isSelected) => Padding( // popupProps: PopupProps.menu(
// padding: const EdgeInsets.symmetric( // showSearchBox: true, // Enables search functionality
// horizontal: 10.0, // menuProps: const MenuProps(backgroundColor: Colors.white),
// vertical: 8.0, // constraints: BoxConstraints(maxHeight: 250),
// ), // itemBuilder:
// child: Text( // (context, item, isSelected) => Padding(
// item, // padding: const EdgeInsets.symmetric(
// style: GoogleFonts.poppins(fontSize: 11.5), // horizontal: 10.0,
// ), // vertical: 8.0,
// ), // ),
// searchFieldProps: TextFieldProps( // child: Text(
// decoration: InputDecoration( // item,
// hintText: "Search ...", // style: GoogleFonts.poppins(fontSize: 11.5),
// hintStyle: GoogleFonts.poppins(fontSize: 11), // ),
// contentPadding: EdgeInsets.symmetric(horizontal: 4), // ),
// ), // searchFieldProps: TextFieldProps(
// ), // decoration: InputDecoration(
// ), // hintText: "Search ...",
// items: countryMap.values.toList(), // hintStyle: GoogleFonts.poppins(fontSize: 11),
// dropdownDecoratorProps: DropDownDecoratorProps( // contentPadding: EdgeInsets.symmetric(horizontal: 4),
// dropdownSearchDecoration: InputDecoration( // ),
// // border: InputBorder.none, // ),
// border: OutlineInputBorder( // ),
// borderRadius: BorderRadius.circular(8), // items: countryMap.values.toList(),
// borderSide: BorderSide( // dropdownDecoratorProps: DropDownDecoratorProps(
// color: // dropdownSearchDecoration: InputDecoration(
// (focusStates["country_codeFocused"] ?? false) // // border: InputBorder.none,
// ? widget.layoutColor! // border: OutlineInputBorder(
// : Colors.white, // borderRadius: BorderRadius.circular(8),
// // width: 0.5, // borderSide: BorderSide(
// ), // color:
// ), // (focusStates["country_codeFocused"] ?? false)
// enabledBorder: OutlineInputBorder( // ? widget.layoutColor!
// borderSide: BorderSide( // : Colors.white,
// color: // // width: 0.5,
// (focusStates["country_codeFocused"] ?? false) // ),
// ? widget.layoutColor! // ),
// : Colors.white, // enabledBorder: OutlineInputBorder(
// // : const Color(0xFFD6D5E6), // borderSide: BorderSide(
// // width: 0.5, // color:
// // const Color(0xFFD6D5E6), // (focusStates["country_codeFocused"] ?? false)
// ), // ? widget.layoutColor!
// ), // : Colors.white,
// focusedBorder: OutlineInputBorder( // // : const Color(0xFFD6D5E6),
// borderSide: BorderSide(color: widget.layoutColor!, width: 1), // // width: 0.5,
// ), // // const Color(0xFFD6D5E6),
// contentPadding: EdgeInsets.symmetric(horizontal: 10.0, // ),
// vertical: 8.0,), // ),
// ), // focusedBorder: OutlineInputBorder(
// ), // borderSide: BorderSide(color: widget.layoutColor!, width: 1),
// dropdownBuilder: // ),
// (context, selectedItem) => Align( // contentPadding: EdgeInsets.symmetric(horizontal: 10.0,
// // Center-align selected item // vertical: 8.0,),
// alignment: Alignment.centerLeft, // ),
// child: Text( // ),
// selectedItem ?? "Select ", // dropdownBuilder:
// style: GoogleFonts.poppins(fontSize: 11), // (context, selectedItem) => Align(
// ), // // Center-align selected item
// ), // alignment: Alignment.centerLeft,
// onChanged: (String? newValue) { // child: Text(
// setState(() { // selectedItem ?? "Select ",
// // Find the country_code based on selected country_name // style: GoogleFonts.poppins(fontSize: 11),
// selectedCountry = // ),
// countryMap.entries // ),
// .firstWhere((entry) => entry.value == newValue) // onChanged: (String? newValue) {
// .key; // setState(() {
// selectedCountryName = newValue; // // Find the country_code based on selected country_name
// setCurrencyFromSelectedCountry(selectedCountry!); // selectedCountry =
// }); // countryMap.entries
// }, // .firstWhere((entry) => entry.value == newValue)
// ), // .key;
) // selectedCountryName = newValue;
) // setCurrencyFromSelectedCountry(selectedCountry!);
// });
// },
// ),
),
),
), ),
), ),
if (errorMessages["country_code"] != null) ...[ if (errorMessages["country_code"] != null) ...[
@ -913,22 +944,23 @@ class ForexDataState extends State<ForexData> {
// // You can get text from commentController.text // // You can get text from commentController.text
// // Navigator.of(context).pop(); // Close the modal // // Navigator.of(context).pop(); // Close the modal
// }, // },
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -168,6 +168,7 @@ class ForexDataListState extends State<ForexDataList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -193,6 +194,7 @@ class ForexDataListState extends State<ForexDataList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -368,9 +370,10 @@ class ForexDataListState extends State<ForexDataList> {
return input return input
.toLowerCase() .toLowerCase()
.split(' ') .split(' ')
.map((word) => word.isNotEmpty .map(
? word[0].toUpperCase() + word.substring(1) (word) =>
: '') word.isNotEmpty ? word[0].toUpperCase() + word.substring(1) : '',
)
.join(' '); .join(' ');
} }
@ -464,15 +467,13 @@ class ForexDataListState extends State<ForexDataList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Perdiem Amount Details',
), ),
BreadcrumbItem(title: 'Perdiem Amount Details'),
], ],
), ),
), ),
@ -488,8 +489,8 @@ class ForexDataListState extends State<ForexDataList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.1), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -634,7 +635,7 @@ class ForexDataListState extends State<ForexDataList> {
future: futureForex, future: futureForex,
builder: (context, snapshot) { builder: (context, snapshot) {
if (futureForex == null) { if (futureForex == null) {
return const CircularProgressIndicator(); return const Center(child: CircularProgressIndicator());
} }
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
@ -790,7 +791,8 @@ class ForexDataListState extends State<ForexDataList> {
), ),
DataCell( DataCell(
Text( Text(
toTitleCase(forex['country_name']) ?? '', toTitleCase(forex['country_name']) ??
'',
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
@ -921,7 +923,8 @@ class ForexDataListState extends State<ForexDataList> {
MainAxisAlignment.spaceBetween, MainAxisAlignment.spaceBetween,
children: [ children: [
Text( Text(
toTitleCase(forex['country_name']) ?? 'N/A', toTitleCase(forex['country_name']) ??
'N/A',
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 10, fontSize: 10,
color: Colors.black87, color: Colors.black87,

View File

@ -824,6 +824,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -964,6 +965,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1010,6 +1012,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1081,6 +1084,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1139,6 +1143,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1289,6 +1294,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(data), body: jsonEncode(data),
); );
@ -1500,6 +1506,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(planData), // Convert map to JSON body: jsonEncode(planData), // Convert map to JSON
); );

View File

@ -300,6 +300,7 @@ class _ListPlansState extends State<ListPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -332,6 +333,7 @@ class _ListPlansState extends State<ListPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(planData), // Convert map to JSON body: jsonEncode(planData), // Convert map to JSON
); );
@ -446,6 +448,7 @@ class _ListPlansState extends State<ListPlans> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );

View File

@ -595,6 +595,7 @@ class _PolicyState extends State<Policy> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(policyData), // Convert map to JSON body: jsonEncode(policyData), // Convert map to JSON
); );

View File

@ -139,10 +139,12 @@ class _PolicyListState extends State<PolicyList> {
filteredPolicy = filteredPolicy =
allPolicy.where((object) { allPolicy.where((object) {
final isActiveStatus = final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive"; object['is_active'] == "1" ? "active" : "inactive";
return (object['policy_id']?.toLowerCase().contains(lowerQuery) ?? false) || return (object['policy_id']?.toLowerCase().contains(lowerQuery) ??
false) ||
(object['name']?.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)); (isActiveStatus.contains(lowerQuery));
}).toList(); }).toList();
currentPage = 0; currentPage = 0;
@ -185,6 +187,7 @@ class _PolicyListState extends State<PolicyList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(policyData), // Convert map to JSON body: jsonEncode(policyData), // Convert map to JSON
); );
@ -339,15 +342,13 @@ class _PolicyListState extends State<PolicyList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Policy',
), ),
BreadcrumbItem(title: 'Policy'),
], ],
), ),
), ),
@ -363,8 +364,8 @@ class _PolicyListState extends State<PolicyList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.145), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -1029,32 +1030,34 @@ class _PolicyListState extends State<PolicyList> {
children: [ children: [
Expanded( Expanded(
child: child:
isDesktop isDesktop
? (searchController.text.isNotEmpty && filteredPolicy.isEmpty ? (searchController.text.isNotEmpty &&
? Center( filteredPolicy.isEmpty
child: Text( "No Matches Found", ? Center(
style: GoogleFonts.poppins( child: Text(
fontSize: 14,
color: Colors.grey,
),),
)
: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: table,
)
)
: (searchController.text.isNotEmpty && filteredPolicy.isEmpty
? Center(
child: Text(
"No Matches Found", "No Matches Found",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 14, fontSize: 14,
color: Colors.grey, 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( PaginationControls(
currentPage: currentPage, currentPage: currentPage,

View File

@ -105,6 +105,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -168,7 +169,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postPurposeOfTravelData(); postPurposeOfTravelData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -212,6 +213,7 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(purposeOfTravelData); final body = jsonEncode(purposeOfTravelData);
@ -429,22 +431,23 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
// ), // ),
SizedBox( SizedBox(
child: ElevatedButton( child: ElevatedButton(
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -132,7 +132,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
} }
Future<List<dynamic>> fetchGetPurposeOfTravel() async { 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(); final String? token = await getToken();
@ -148,6 +149,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
print("called api : $apiUrlData"); print("called api : $apiUrlData");
@ -180,11 +182,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
allPurposeOfTravel.where((object) { allPurposeOfTravel.where((object) {
final isActiveStatus = final isActiveStatus =
object['is_active'] == "1" ? "active" : "inactive"; object['is_active'] == "1" ? "active" : "inactive";
return (object['id']?.toLowerCase().contains( return (object['id']?.toLowerCase().contains(lowerQuery) ??
lowerQuery, false) ||
) ?? (object['dropdown_value']?.toLowerCase().contains(lowerQuery) ??
false) || false) ||
(object['dropdown_value']?.toLowerCase().contains(lowerQuery) ?? false) ||
// (object['description']?.toLowerCase().contains(lowerQuery) ?? // (object['description']?.toLowerCase().contains(lowerQuery) ??
// false) || // false) ||
(isActiveStatus.contains(lowerQuery)); (isActiveStatus.contains(lowerQuery));
@ -284,15 +285,13 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Purpose Of Travel Details',
), ),
BreadcrumbItem(title: 'Purpose Of Travel Details'),
], ],
), ),
), ),
@ -308,8 +307,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.08), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -583,10 +582,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
rows: rows:
paginatedPurposeOfTravel.map((tableObject) { paginatedPurposeOfTravel.map((tableObject) {
String purposeOfTravelId = String purposeOfTravelId =
tableObject['id'] tableObject['id'].toString(); // Get user ID
.toString(); // Get user ID
bool isSelected = bool isSelected =
selectedPurposeOfTravelId == purposeOfTravelId; selectedPurposeOfTravelId ==
purposeOfTravelId;
return DataRow( return DataRow(
cells: [ cells: [
@ -635,7 +634,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
// ), // ),
GestureDetector( GestureDetector(
child: Tooltip( child: Tooltip(
message: 'Edit Purpose Of Travel Details', message:
'Edit Purpose Of Travel Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
@ -646,10 +646,10 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
// final userId = getUserId(user['user_id']); // final userId = getUserId(user['user_id']);
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final purposeOfTravelId = int.tryParse( final purposeOfTravelId =
tableObject['id'] int.tryParse(
.toString(), tableObject['id'].toString(),
); );
if (purposeOfTravelId != null) { if (purposeOfTravelId != null) {
print( print(
@ -664,7 +664,9 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
showDialog( showDialog(
context: context, context: context,
builder: builder:
(context) => PurposeOfTravelData( (
context,
) => PurposeOfTravelData(
isDesktop: isDesktop, isDesktop: isDesktop,
purposeOfTravelId: purposeOfTravelId:
purposeOfTravelId, // Pass the ID purposeOfTravelId, // Pass the ID
@ -728,7 +730,8 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
GestureDetector( GestureDetector(
child: Tooltip( child: Tooltip(
message: 'Edit Purpose Of Travel Details', message:
'Edit Purpose Of Travel Details',
child: Image.asset( child: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
width: 20, width: 20,
@ -740,8 +743,7 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
// final usersData = await getUserDetails(userId); // final usersData = await getUserDetails(userId);
// //
final purposeOfTravelId = int.tryParse( final purposeOfTravelId = int.tryParse(
cardObject['id'] cardObject['id'].toString(),
.toString(),
); );
if (purposeOfTravelId != null) { if (purposeOfTravelId != null) {
@ -757,7 +759,9 @@ class PurposeOfTravelListState extends State<PurposeOfTravelList> {
showDialog( showDialog(
context: context, context: context,
builder: builder:
(context) => PurposeOfTravelData( (
context,
) => PurposeOfTravelData(
isDesktop: isDesktop, isDesktop: isDesktop,
purposeOfTravelId: purposeOfTravelId:
purposeOfTravelId, // Pass the ID purposeOfTravelId, // Pass the ID

View File

@ -106,6 +106,7 @@ class TravellerDataState extends State<TravellerData> {
} }
super.dispose(); super.dispose();
} }
void _addFocusListener(FocusNode node, Function(bool) updateState) { void _addFocusListener(FocusNode node, Function(bool) updateState) {
node.addListener(() { node.addListener(() {
setState(() { setState(() {
@ -188,7 +189,7 @@ class TravellerDataState extends State<TravellerData> {
// This triggers UI rebuild with error messages // This triggers UI rebuild with error messages
if (validateData()) { if (validateData()) {
postTravellerData(); postTravellerData();
}else{ } else {
isDisable = false; isDisable = false;
} }
}); });
@ -235,6 +236,7 @@ class TravellerDataState extends State<TravellerData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode(travellerData); final body = jsonEncode(travellerData);
@ -550,22 +552,23 @@ class TravellerDataState extends State<TravellerData> {
// ), // ),
SizedBox( SizedBox(
child: ElevatedButton( child: ElevatedButton(
onPressed: isDisable onPressed:
? null isDisable
: () async { ? null
setState(() { : () async {
isDisable = true; setState(() {
}); isDisable = true;
});
await handleSubmit(); await handleSubmit();
// You can get text from commentController.text // You can get text from commentController.text
// Navigator.of(context).pop(); // Close the modal // Navigator.of(context).pop(); // Close the modal
// Optional: re-enable only on error // Optional: re-enable only on error
// setState(() { // setState(() {
// isDisable = false; // isDisable = false;
// }); // });
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColor, backgroundColor: widget.layoutColor,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(

View File

@ -151,6 +151,7 @@ class TravellerListState extends State<TravellerList> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
print("called api : $apiUrlData"); print("called api : $apiUrlData");
@ -294,15 +295,13 @@ class TravellerListState extends State<TravellerList> {
isDesktop: isDesktop, isDesktop: isDesktop,
breadcrumbItems: [ breadcrumbItems: [
BreadcrumbItem( BreadcrumbItem(
title: 'Org Settings', title: 'Org Settings',
tooltip: 'Go To Organization Settings', tooltip: 'Go To Organization Settings',
onTap: (context) { onTap: (context) {
context.go("/OrganizationSettings"); context.go("/OrganizationSettings");
} },
),
BreadcrumbItem(
title: 'Traveller Details',
), ),
BreadcrumbItem(title: 'Traveller Details'),
], ],
), ),
), ),
@ -318,8 +317,8 @@ class TravellerListState extends State<TravellerList> {
), ),
if (isDesktop) if (isDesktop)
SizedBox(width: MediaQuery.of(context).size.width * 0.10), 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) if (isDesktop)
Container( Container(
width: MediaQuery.of(context).size.width * 0.2, width: MediaQuery.of(context).size.width * 0.2,
@ -466,7 +465,7 @@ class TravellerListState extends State<TravellerList> {
builder: (context, snapshot) { builder: (context, snapshot) {
final adjHgt = MediaQuery.of(context).size.height; final adjHgt = MediaQuery.of(context).size.height;
if (futureTraveller == null) { if (futureTraveller == null) {
return CircularProgressIndicator(); return const Center(child: CircularProgressIndicator());
} }
if (snapshot.connectionState == ConnectionState.waiting) { if (snapshot.connectionState == ConnectionState.waiting) {

View File

@ -990,6 +990,7 @@ class _CreateTravelAgentFormDetialsState
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {

View File

@ -12,43 +12,35 @@ import '../../../services/apiService.dart';
import '../../../utils/auth_utils.dart'; import '../../../utils/auth_utils.dart';
import '../../../widgets/custom_user_form.dart'; import '../../../widgets/custom_user_form.dart';
class ChangePasswordDialogData extends StatefulWidget { class ChangePasswordDialogData extends StatefulWidget {
final dynamic isDesktop; final dynamic isDesktop;
final dynamic layoutColor; final dynamic layoutColor;
final dynamic updaterUserId; final dynamic updaterUserId;
final dynamic updaterEmail; final dynamic updaterEmail;
const ChangePasswordDialogData({ const ChangePasswordDialogData({
super.key, super.key,
this.isDesktop, this.isDesktop,
this.layoutColor, this.layoutColor,
this.updaterUserId, this.updaterUserId,
this.updaterEmail this.updaterEmail,
}); });
@override
@override ChangePasswordDialogDataState createState() =>
ChangePasswordDialogDataState createState() => ChangePasswordDialogDataState(); ChangePasswordDialogDataState();
} }
class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> { class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
final Map<String, TextEditingController> controllers = {}; final Map<String, TextEditingController> controllers = {};
Map<String, String> errorMessages = {}; Map<String, String> errorMessages = {};
String? loggeduserId; String? loggeduserId;
String? updaterUserIdForAPI; String? updaterUserIdForAPI;
List<String> dataHeader = [ List<String> dataHeader = ["email", "changePassword", "confirmPassword"];
"email",
"changePassword",
"confirmPassword"
];
// @override // @override
// void initState() { // void initState() {
@ -75,15 +67,13 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
} }
setState(() { setState(() {
controllers['email']?.text = widget.updaterEmail ; controllers['email']?.text = widget.updaterEmail;
controllers['changePassword']?.text = ''; controllers['changePassword']?.text = '';
controllers['confirmPassword']?.text = ''; controllers['confirmPassword']?.text = '';
updaterUserIdForAPI = widget.updaterUserId; updaterUserIdForAPI = widget.updaterUserId;
}); });
} }
void _clearError() { void _clearError() {
setState(() { setState(() {
errorMessages.clear(); errorMessages.clear();
@ -98,40 +88,37 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
super.dispose(); super.dispose();
} }
bool validateData() { bool validateData() {
errorMessages.clear(); errorMessages.clear();
final String? email = controllers["email"]?.text; final String? email = controllers["email"]?.text;
final String? changePassword = controllers["changePassword"]?.text; final String? changePassword = controllers["changePassword"]?.text;
final String? confirmPassword = controllers["confirmPassword"]?.text; final String? confirmPassword = controllers["confirmPassword"]?.text;
// Required fields check // Required fields check
if (email == null || email.trim().isEmpty) { if (email == null || email.trim().isEmpty) {
errorMessages["email"] = "Required"; 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;
} }
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 { Future<void> handleSubmit() async {
loggeduserId = await getUserId(); loggeduserId = await getUserId();
@ -142,7 +129,6 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
postData(); postData();
} }
}); });
} }
Future<void> postData() async { Future<void> postData() async {
@ -152,12 +138,14 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
final password = controllers["changePassword"]?.text ?? ''; final password = controllers["changePassword"]?.text ?? '';
final confirmPassword = controllers["confirmPassword"]?.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 token = await getToken();
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
try { try {
@ -165,6 +153,7 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
final headers = { final headers = {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}; };
final body = jsonEncode({ final body = jsonEncode({
"password": password, "password": password,
@ -200,7 +189,6 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30), contentPadding: const EdgeInsets.fromLTRB(34, 30, 34, 30),
@ -220,10 +208,7 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
], ],
), ),
const SizedBox(height: 2), const SizedBox(height: 2),
Divider( Divider(thickness: 0.2, color: Colors.blueGrey.shade100),
thickness: 0.2,
color: Colors.blueGrey.shade100,
),
const SizedBox(height: 5), const SizedBox(height: 5),
Column( Column(
@ -232,9 +217,10 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
Text( Text(
"Email", "Email",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
@ -245,18 +231,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
// ? MediaQuery.of(context).size.width * 0.330 // ? MediaQuery.of(context).size.width * 0.330
// : MediaQuery.of(context).size.width * 0.66, // : MediaQuery.of(context).size.width * 0.66,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
controller: controllers["email"], controller: controllers["email"],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Email", labelText: "Email",
labelStyle: TextStyle(fontSize: 11, color: Colors.grey), labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
), ),
)), ),
),
), ),
if (errorMessages["email"] != null) ...[ if (errorMessages["email"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
@ -267,18 +254,17 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
], ],
], ],
), ),
SizedBox( SizedBox(height: 10),
height: 10,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Change Password", "Change Password",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
@ -286,18 +272,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
color: Colors.transparent, color: Colors.transparent,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
controller: controllers["changePassword"], controller: controllers["changePassword"],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Change Password", labelText: "Change Password",
labelStyle: TextStyle(fontSize: 11, color: Colors.grey), labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
), ),
)), ),
),
), ),
if (errorMessages["changePassword"] != null) ...[ if (errorMessages["changePassword"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
@ -308,18 +295,17 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
], ],
], ],
), ),
SizedBox( SizedBox(height: 15),
height: 15,
),
Column( Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Confirm Password", "Confirm Password",
style: GoogleFonts.poppins( style: GoogleFonts.poppins(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF575A74)), color: Color(0xFF575A74),
),
), ),
SizedBox(height: 5), SizedBox(height: 5),
CustomTextFieldUserWrapper( CustomTextFieldUserWrapper(
@ -327,18 +313,19 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
isDesktop: widget.isDesktop, isDesktop: widget.isDesktop,
color: Colors.transparent, color: Colors.transparent,
child: SizedBox( child: SizedBox(
height: 40, height: 40,
child: TextField( child: TextField(
controller: controllers["confirmPassword"], controller: controllers["confirmPassword"],
style: const TextStyle(fontSize: 12), style: const TextStyle(fontSize: 12),
decoration: const InputDecoration( decoration: const InputDecoration(
labelText: "Confirm Password", labelText: "Confirm Password",
labelStyle: TextStyle(fontSize: 11, color: Colors.grey), labelStyle: TextStyle(fontSize: 11, color: Colors.grey),
floatingLabelBehavior: FloatingLabelBehavior.never, floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16), contentPadding: EdgeInsets.symmetric(vertical: 16),
), ),
)), ),
),
), ),
if (errorMessages["confirmPassword"] != null) ...[ if (errorMessages["confirmPassword"] != null) ...[
SizedBox(height: 5), // Space before error message SizedBox(height: 5), // Space before error message
@ -349,9 +336,7 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
], ],
], ],
), ),
SizedBox( SizedBox(height: 15),
height: 15,
),
Row( Row(
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
@ -367,17 +352,20 @@ class ChangePasswordDialogDataState extends State<ChangePasswordDialogData> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
child: Text('Save', child: Text(
style: GoogleFonts.poppins( 'Save',
fontSize: 11, color: Colors.white)), style: GoogleFonts.poppins(
fontSize: 11,
color: Colors.white,
),
),
), ),
), ),
], ],
) ),
// : SizedBox.shrink(), // : SizedBox.shrink(),
], ],
), ),
); );
} }
} }

View File

@ -1259,6 +1259,7 @@ class _CreateUserFormDetialsState extends State<CreateUserFormDetials> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style
if (isUpdating) { if (isUpdating) {

View File

@ -161,6 +161,7 @@ class _UserListScreenState extends State<UserListScreen> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -186,6 +187,7 @@ class _UserListScreenState extends State<UserListScreen> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', '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 // Attach the file to the request
// Set authorization token in headers // Set authorization token in headers
request.headers['Authorization'] = 'Bearer $token'; 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(http.MultipartFile.fromBytes('file', fileBytes, filename: fileName));
request.files.add( request.files.add(
@ -718,6 +723,7 @@ class _UserListScreenState extends State<UserListScreen> {
// Use MultipartRequest (POST only) // Use MultipartRequest (POST only)
final request = http.MultipartRequest('POST', uri); final request = http.MultipartRequest('POST', uri);
request.headers['Authorization'] = 'Bearer $token'; request.headers['Authorization'] = 'Bearer $token';
request.headers['app-signature'] = 'ts-traveltool-2025-signature-123456';
// If updating, spoof the method Laravel-style // If updating, spoof the method Laravel-style

View File

@ -34,8 +34,8 @@ class _MyAppState extends State<MyApp> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
SemanticsBinding.instance // SemanticsBinding.instance
.ensureSemantics(); // -only for testing uncomment, Otherwise Email Template wont allow to type // .ensureSemantics(); // -only for testing uncomment, Otherwise Email Template wont allow to type
if (kIsWeb) { if (kIsWeb) {
final uri = Uri.parse(html.window.location.href); final uri = Uri.parse(html.window.location.href);
print("URI - $uri"); print("URI - $uri");
@ -87,7 +87,7 @@ class _MyAppState extends State<MyApp> {
print("handleTokenUsingMS- $authCode"); print("handleTokenUsingMS- $authCode");
try { try {
// final url = 'http://localhost:43627/tstat/auth/verifyMSAuthUser?code=$authCode'; // 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"); print("Microsoft BE URL - $url");
final response = await http.get( final response = await http.get(
Uri.parse(url), Uri.parse(url),

View File

@ -44,6 +44,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -80,6 +81,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -116,6 +118,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -156,6 +159,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -185,6 +189,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -240,6 +245,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -291,6 +297,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -330,6 +337,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -367,6 +375,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -404,6 +413,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -441,6 +451,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -476,6 +487,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -518,6 +530,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -559,6 +572,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -583,6 +597,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', // Add token here 'Authorization': 'Bearer $token', // Add token here
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -664,6 +679,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -710,6 +726,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -747,6 +764,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -786,6 +804,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -850,6 +869,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -915,6 +935,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
// 'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -965,6 +986,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1010,6 +1032,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1054,6 +1077,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1100,6 +1124,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1146,6 +1171,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1200,6 +1226,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1346,6 +1373,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1392,6 +1420,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1438,6 +1467,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1480,6 +1510,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -1534,6 +1565,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
if (response.statusCode == 200) { if (response.statusCode == 200) {
@ -1573,6 +1605,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: body, body: body,
); );
@ -1616,6 +1649,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: body, body: body,
); );
@ -1673,6 +1707,7 @@ class ApiService {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );

View File

@ -122,6 +122,7 @@ class CommentModalState extends State<CommentModal> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
); );
@ -143,7 +144,8 @@ class CommentModalState extends State<CommentModal> {
print("Res1 - $data"); print("Res1 - $data");
if (!data.containsKey('data') || data['data'] is! Map) { if (!data.containsKey('data') || data['data'] is! Map) {
throw Exception( 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']; return data['data'];
} else { } else {
@ -186,6 +188,7 @@ class CommentModalState extends State<CommentModal> {
headers: { headers: {
'Authorization': 'Bearer $token', 'Authorization': 'Bearer $token',
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'app-signature': 'ts-traveltool-2025-signature-123456',
}, },
body: jsonEncode(remarksData), // Convert map to JSON body: jsonEncode(remarksData), // Convert map to JSON
); );
@ -255,7 +258,8 @@ class CommentModalState extends State<CommentModal> {
icon: const Icon(Icons.delete, size: 20), icon: const Icon(Icons.delete, size: 20),
onPressed: () async { onPressed: () async {
await postRemarksData( await postRemarksData(
isActive: 0); // Marks the remark as deleted isActive: 0,
); // Marks the remark as deleted
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
), ),
@ -280,27 +284,30 @@ class CommentModalState extends State<CommentModal> {
const SizedBox(height: 20), const SizedBox(height: 20),
// Row 3: OK button // Row 3: OK button
editRemarks editRemarks
? SizedBox( ? SizedBox(
width: double.infinity, width: double.infinity,
child: ElevatedButton( child: ElevatedButton(
onPressed: () { onPressed: () {
postRemarksData(); postRemarksData();
// You can get text from commentController.text // You can get text from commentController.text
Navigator.of(context).pop(); // Close the modal Navigator.of(context).pop(); // Close the modal
}, },
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: widget.layoutColorForUser, backgroundColor: widget.layoutColorForUser,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), 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(), : SizedBox.shrink(),
], ],
), ),

View File

@ -609,10 +609,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: mime name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "1.0.6"
nested: nested:
dependency: transitive dependency: transitive
description: description: