ui_input_formatters

This commit is contained in:
venbaittech 2025-10-27 17:35:57 +05:30
parent 52878d6810
commit aaff31e8d4
43 changed files with 1069 additions and 648 deletions

View File

@ -204,7 +204,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
Future<List<Plan>> fetchPlans() async {
late String apiUrldata;
apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
apiUrldata = '$apiUrl/api/allPlans?org_id=$orgId';
// if (roleUser == "Org Admin") {
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
@ -283,7 +284,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
bool confirmed = await apiService.showCancelConfirmationDialog(
context,
layoutColor,
@ -293,6 +294,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
try {
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
@ -1135,6 +1137,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1455,6 +1458,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),

View File

@ -143,14 +143,17 @@ class _TripInformationState extends State<TripInformation> {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
keyValueRow("Action", item["action"]),
keyValueRow("Approver", item["approver"]),
keyValueRow("Action", item["action"] ?? '-'),
keyValueRow("Approver", item["approver"] ?? '-'),
keyValueRow(
"Is Action Done",
item["is_action_done"],
item["is_action_done"] ?? '-',
),
keyValueRow("Action On", item["action_on"] ?? '-'),
keyValueRow(
"Email Status",
item["email_status"] ?? '-',
),
keyValueRow("Action On", item["action_on"]),
keyValueRow("Email Status", item["email_status"]),
],
),
),

View File

@ -364,6 +364,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
try {
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Future<dynamic> showApprovalDialog(
BuildContext context,
@ -115,6 +116,11 @@ Future<dynamic> showApprovalDialog(
TextField(
style: TextStyle(fontFamily: "Inter", fontSize: 14),
maxLines: 3,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
onChanged: (value) => remarks = value,
decoration: InputDecoration(
hintText: "Remarks...",
@ -263,8 +269,14 @@ Future<String?> showRejectDialog1(
const Text("Please enter reason for rejection."),
const SizedBox(height: 10),
TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
maxLines: 3,
onChanged: (value) => remarks = value,
decoration: const InputDecoration(
hintText: "Remarks...",
hintStyle: TextStyle(

View File

@ -256,7 +256,7 @@ class _ApprovalListState extends State<ApprovalList> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
// try {
// Map<String, dynamic> planData = await getViewPlan(planId);
// print("ViewAAA - $planData");
@ -275,6 +275,7 @@ class _ApprovalListState extends State<ApprovalList> {
try {
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
@ -1207,6 +1208,7 @@ class _ApprovalListState extends State<ApprovalList> {
);
deletePlan(
plan.planId,
userId,
);
},
),

View File

@ -4,6 +4,7 @@ import 'dart:html' as html;
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:frontend/config/apiUrl.dart';
import 'package:google_fonts/google_fonts.dart';
@ -580,6 +581,7 @@ class _LoginWidgetState extends State<LoginWidget> {
_buildLabel("Email Address"),
TextFormField(
controller: _emailController,
inputFormatters: [],
style: GoogleFonts.poppins(
fontWeight: FontWeight.w600,
fontSize: 11,

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -314,6 +315,11 @@ class CostCenterDataState extends State<CostCenterData> {
child: TextField(
controller: controllers["name"],
focusNode: focusNodes["nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Name",
@ -356,6 +362,11 @@ class CostCenterDataState extends State<CostCenterData> {
child: TextField(
controller: controllers["description"],
focusNode: focusNodes["descriptionFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
maxLines: null,
expands: true,

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -313,6 +314,11 @@ class DepartmentDataState extends State<DepartmentData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["dropdown_value"],
focusNode: focusNodes["dropdown_valueFocusNode"],
style: const TextStyle(fontSize: 12),

View File

@ -320,6 +320,7 @@ class DepartmentListState extends State<DepartmentList> {
height: 40,
child: TextField(
controller: searchController,
onChanged: filterDepartment,
decoration: InputDecoration(
hintText: "Search ...",

View File

@ -176,11 +176,6 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else if (response.statusCode == 403) {
print("403-FORB");
await apiService.logout(context);
return null;
// throw Exception('Failed to load users');
} else {
throw Exception(
'Failed to load users. Status Code: ${response.statusCode}',

View File

@ -4,6 +4,7 @@ import 'dart:io';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/organization/mailSettings.dart';
import 'package:frontend/Screens/organization/themeColor.dart';
import 'package:frontend/utils/auth_utils.dart';
@ -481,6 +482,9 @@ class _groupState extends State<Group> {
height: 40,
child: TextField(
controller: controllers["name"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
onChanged: (value) {
_clearError("name");
@ -527,6 +531,9 @@ class _groupState extends State<Group> {
height: 40,
child: TextField(
controller: controllers["description"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
_clearError("description");
},

View File

@ -426,7 +426,11 @@ class GroupDataState extends State<GroupData> {
height: 40,
child: TextField(
focusNode: focusNodes["nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["name"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -779,7 +783,11 @@ class GroupDataState extends State<GroupData> {
child: TextField(
controller: controllers["description"],
focusNode: focusNodes["descriptionFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
maxLines: null,
expands: true,

View File

@ -372,6 +372,11 @@ class HotelsDataState extends State<HotelsData> {
height: 40,
child: TextField(
focusNode: focusNodes["hotel_nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["hotel_name"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -415,6 +420,11 @@ class HotelsDataState extends State<HotelsData> {
child: TextField(
focusNode: focusNodes["hotel_chainFocusNode"],
controller: controllers["hotel_chain"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Hotel Chain",
@ -458,9 +468,10 @@ class HotelsDataState extends State<HotelsData> {
child: TextField(
focusNode: focusNodes["categoryFocusNode"],
controller: controllers["category"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 ]'),
RegExp(r'[a-z A-Z0-9 ]'),
),
],
style: const TextStyle(fontSize: 12),
@ -665,6 +676,11 @@ class HotelsDataState extends State<HotelsData> {
height: 40,
child: TextField(
focusNode: focusNodes["cityFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["city"],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -379,6 +380,11 @@ class HotelsDataListState extends State<HotelsDataList> {
height: 40,
child: TextField(
controller: searchController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
onChanged: filterHotels,
decoration: InputDecoration(
hintText: "Search ...",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -664,6 +665,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
focusNode: _destinationFocusNode,
controller: _destinationController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Destination",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1503,6 +1507,9 @@ class _AccomodationScreenState extends State<AccomodationScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _commentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -466,6 +467,9 @@ class _BusScreenState extends State<BusScreen> {
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "From",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -503,6 +507,9 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _toFocusNode,
controller: _toController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "To",
@ -548,6 +555,7 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _dateFocusNode,
controller: _dateController,
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -656,6 +664,9 @@ class _BusScreenState extends State<BusScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _buscommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
@ -2520,6 +2521,9 @@ class FlightScreenState extends State<FlightScreen> {
focusNode: focusNodes["_comments1FocusNode"],
// controller: _commentsController,
controller: textControllers["_comments1Controller"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
// maxLines: 6,
// keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),

View File

@ -1147,6 +1147,11 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_forexStartDate"],
controller: textControllers["_forexStartDate"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: InputDecoration(
@ -1234,6 +1239,11 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_forexEndDate"],
controller: textControllers["_forexEndDate"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -1678,6 +1688,7 @@ class _ForexScreenState extends State<ForexScreen> {
height: 30,
child: TextField(
focusNode: focusNodes["_transport"],
controller: textControllers["_transport"],
onChanged: (value) {
setState(() {
@ -2232,6 +2243,9 @@ class _ForexScreenState extends State<ForexScreen> {
child: TextField(
focusNode: focusNodes["_comments"],
controller: textControllers["_comments"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",
@ -2340,6 +2354,11 @@ class _ForexScreenState extends State<ForexScreen> {
onChanged: (value) {
errorMessages.remove("delivery_location");
},
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Location",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -1180,7 +1181,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
height: 40,
child: TextField(
focusNode: focusNodes["nominee_nameFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
// focusNode: _nomineeFocusNode,
controller: _nomineeController,
style: TextStyle(fontSize: 12),
@ -1290,6 +1293,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
focusNode: focusNodes["nominee_relationshipFocusNode"],
controller: _nomineerelationController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Nominee Relationship",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1340,6 +1346,9 @@ class _InsuranceScreenState extends State<InsuranceScreen> {
// focusNode: _commentsFocusNode,
focusNode: focusNodes["commentsFocusNode"],
controller: _insuranceCommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -125,9 +126,9 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
});
}
@ -309,106 +310,114 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: _hotelNameFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_hotelNameFocused = hasFocus;
});
child: Focus(
focusNode: _hotelNameFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_hotelNameFocused = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_hotelNameFocusNode?.requestFocus();
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_hotelNameFocusNode?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
// focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedSpecialType,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
child: DropdownSearch<Map<String, dynamic>>(
// focusNode: _taxiReqFocusNode,
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedSpecialType,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4),
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
child: Text(
item['dropdown_value'] ?? '',
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(4),
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_hotelNameFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
);
},
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedSpecialType = newValue as String?;
});
print("Updating form data: -> ${newValue ?? ""}");
}
: null,
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(color: Colors.grey, fontSize: 13),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
);
},
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedSpecialType = newValue as String?;
});
print("Updating form data: -> ${newValue ?? ""}");
}
: null,
),),)
),
),
),
if (errorMessages["special_request"] != null) ...[
@ -439,10 +448,13 @@ class _MiscellaneousScreenState extends State<MiscellaneousScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: _commentsFocusNode,
controller: _commentsController,
style: TextStyle(fontSize: 12),

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -11,8 +12,12 @@ class ForexScreen extends StatefulWidget {
final Function(String tab, String key, String value) updateFormData;
final Function(bool) onClose;
ForexScreen({required this.formData, required this.updateFormData,
required this.onClose, this.apiData});
ForexScreen({
required this.formData,
required this.updateFormData,
required this.onClose,
this.apiData,
});
@override
_ForexScreenState createState() => _ForexScreenState();
@ -95,57 +100,55 @@ class _ForexScreenState extends State<ForexScreen> {
});
});
_tripTypeController =
TextEditingController(text: widget.formData["tripType"] ?? "");
_hotelNameController =
TextEditingController(text: widget.formData["_hotelName"] ?? "");
_fromController =
TextEditingController(text: widget.formData["_from"] ?? "");
_toController =
TextEditingController(text: widget.formData["_Check_In_Time"] ?? "");
_dateController =
TextEditingController(text: widget.formData["_Check_Out"] ?? "");
_endDateController =
TextEditingController(text: widget.formData["_Check_In"] ?? "");
_timeController =
TextEditingController(text: widget.formData["_Check_Out_Time"] ?? "");
_commentsController =
TextEditingController(text: widget.formData["_comments"] ?? "");
_tripTypeController = TextEditingController(
text: widget.formData["tripType"] ?? "",
);
_hotelNameController = TextEditingController(
text: widget.formData["_hotelName"] ?? "",
);
_fromController = TextEditingController(
text: widget.formData["_from"] ?? "",
);
_toController = TextEditingController(
text: widget.formData["_Check_In_Time"] ?? "",
);
_dateController = TextEditingController(
text: widget.formData["_Check_Out"] ?? "",
);
_endDateController = TextEditingController(
text: widget.formData["_Check_In"] ?? "",
);
_timeController = TextEditingController(
text: widget.formData["_Check_Out_Time"] ?? "",
);
_commentsController = TextEditingController(
text: widget.formData["_comments"] ?? "",
);
// Save data when user types
_tripTypeController.addListener(() {
widget.updateFormData(
"Bus", "_tripType", _tripTypeController.text);
widget.updateFormData("Bus", "_tripType", _tripTypeController.text);
}); // Save data when user types
_hotelNameController.addListener(() {
widget.updateFormData(
"Bus", "_hotelName", _hotelNameController.text);
widget.updateFormData("Bus", "_hotelName", _hotelNameController.text);
});
_fromController.addListener(() {
widget.updateFormData(
"Bus", "_from", _fromController.text);
widget.updateFormData("Bus", "_from", _fromController.text);
});
_toController.addListener(() {
widget.updateFormData(
"Bus", "_Check_In_Time", _toController.text);
widget.updateFormData("Bus", "_Check_In_Time", _toController.text);
});
_dateController.addListener(() {
widget.updateFormData(
"Bus", "_Check_Out", _dateController.text);
widget.updateFormData("Bus", "_Check_Out", _dateController.text);
});
_endDateController.addListener(() {
widget.updateFormData(
"Bus", "_Check_In", _endDateController.text);
widget.updateFormData("Bus", "_Check_In", _endDateController.text);
});
_timeController.addListener(() {
widget.updateFormData(
"Bus", "_Check_Out_Time", _timeController.text);
widget.updateFormData("Bus", "_Check_Out_Time", _timeController.text);
});
_commentsController.addListener(() {
widget.updateFormData(
"Bus", "_comments", _commentsController.text);
widget.updateFormData("Bus", "_comments", _commentsController.text);
});
}
@ -163,56 +166,60 @@ class _ForexScreenState extends State<ForexScreen> {
super.dispose();
}
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return ResponsiveBuilder(
builder: (context, sizingInfo) {
bool isMobile = sizingInfo.isMobile;
bool isDesktop =
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
return Container(
color: Color(0xFFF4F4FB),
child: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
widget.onClose(false);
},
child: Icon(
Icons.close,
size: 18,
return Container(
color: Color(0xFFF4F4FB),
child: Form(
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Align(
alignment: Alignment.centerRight,
child: InkWell(
onTap: () {
widget.onClose(false);
},
child: Icon(
Icons.close,
size: 18,
color: Color(0xFF575A74),
),
),
),
Text(
"Forex List",
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Color(0xFF575A74),
),
),
),
Text("Forex List",
style:
TextStyle(fontSize: 18, fontWeight: FontWeight.bold,color: Color(0xFF575A74))),
SizedBox(
height: 6,
),
Padding(
padding: const EdgeInsets.all(28.0),
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
SizedBox(height: 6),
Padding(
padding: const EdgeInsets.all(28.0),
child: Center(
child: Column(children: _buildAccomadtionForm(isDesktop)),
),
),
)
],
],
),
),
),
),
);
});
);
},
);
}
List<Widget> _buildAccomadtionForm (bool isDesktop) {
List<Widget> _buildAccomadtionForm(bool isDesktop) {
List<Widget> buildResponsiveRow(List<Widget> children) {
return [
isDesktop ? Row(children: children) : Column(children: children),
@ -222,14 +229,12 @@ class _ForexScreenState extends State<ForexScreen> {
List<List<Widget>> rowBuilders = [
_builClassType(isDesktop),
_buildSecondRow(isDesktop)
_buildSecondRow(isDesktop),
];
return [
...buildResponsiveRow(_buildFirstRow(isDesktop)),
// Iterate over rowBuilders and wrap each in a responsive container
...rowBuilders.expand((row) => buildResponsiveRow(row)),
@ -247,23 +252,21 @@ class _ForexScreenState extends State<ForexScreen> {
];
}
List<Widget> _buildFirstRow(isDesktop) {
DateTime? _selectedCheckOutDate;
DateTime? _selectedEndDate;
Future<void> _selectCheckOutDate(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedCheckOutDate != null && _selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate!
: today,
initialDate:
_selectedCheckOutDate != null &&
_selectedCheckOutDate!.isAfter(today)
? _selectedCheckOutDate!
: today,
firstDate: today,
lastDate: DateTime(2100),
);
@ -274,18 +277,20 @@ class _ForexScreenState extends State<ForexScreen> {
_dateController.text = DateFormat('yyyy-MM-dd').format(pickedDate);
});
}
};
}
;
Future<void> _selectForexEndDate(BuildContext context) async {
DateTime now = DateTime.now();
DateTime today = DateTime(now.year, now.month, now.day);
DateTime? pickedDate = await showDatePicker(
context: context,
initialDate: _selectedEndDate != null && _selectedEndDate!.isAfter(today)
? _selectedEndDate!
: today,
initialDate:
_selectedEndDate != null && _selectedEndDate!.isAfter(today)
? _selectedEndDate!
: today,
firstDate: today,
lastDate: DateTime(2100),
);
@ -298,7 +303,6 @@ class _ForexScreenState extends State<ForexScreen> {
}
}
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -306,9 +310,10 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Forex Start Date",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -330,32 +335,30 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today,
size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Forex End Date",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -377,46 +380,50 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
suffixIcon: Icon(Icons.calendar_today,
size: 16, color: Colors.grey),
suffixIcon: Icon(
Icons.calendar_today,
size: 16,
color: Colors.grey,
),
),
),
),
),
),
),
],
),
];
}
List<Widget> _buildTripType(bool isDesktop){
List<Widget> _buildTripType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_trip_type'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
CustomTextFieldWrapper(
@ -432,51 +439,62 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
print("Updating form data: Flight -> trip_type -> ${newValue ?? ""}");
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
print(
"Updating form data: Flight -> trip_type -> ${newValue ?? ""}",
);
widget.updateFormData("Flight", "trip_type", newValue ?? "");
}
: null,
widget.updateFormData(
"Flight",
"trip_type",
newValue ?? "",
);
}
: null,
items: dropdownItems,
),
),
),
];
}
List<Widget> _builClassType(bool isDesktop){
List<Widget> _builClassType(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
Column(
@ -485,9 +503,10 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Class *",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
@ -504,15 +523,17 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
items: dropdownItems,
),
@ -535,27 +556,30 @@ class _ForexScreenState extends State<ForexScreen> {
];
}
List<Widget> _buildSecondRow(bool isDesktop) {
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Transport",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: _fromFocus,
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -565,28 +589,23 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Accomodation",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -611,21 +630,17 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Telephone",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -633,7 +648,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -643,34 +658,29 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Other Expenses",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
isFocused: _toFocus,
isDesktop: isDesktop,
color:Colors.transparent,
color: Colors.transparent,
child: SizedBox(
height: 40,
@ -680,7 +690,11 @@ class _ForexScreenState extends State<ForexScreen> {
"Rs ",
// focusNode: _toFocusNode,
// controller: _toController,
style: const TextStyle(fontSize: 18, fontWeight: FontWeight.w600,color: Color(0xFF575A74)),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
// decoration: const InputDecoration(
// labelText: "To",
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -694,43 +708,48 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
];
}
List<Widget> _buildCardDetailsRow(bool isDesktop) {
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
List<DropdownMenuItem<String>> dropdownItems = purposeList
.map((item)=>DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
)).toList();
List<DropdownMenuItem<String>> dropdownItems =
purposeList
.map(
(item) => DropdownMenuItem<String>(
value: item['dropdown_value'],
child: Text(item['dropdown_value']),
),
)
.toList();
if (dropdownItems.isEmpty) {
dropdownItems.add(
DropdownMenuItem<String>(
value: null,
child: Text("No options available", style: TextStyle(color: Colors.grey)),
child: Text(
"No options available",
style: TextStyle(color: Colors.grey),
),
),
);
}
// Default selected value
String? selectedPurpose = dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
String? selectedPurpose =
dropdownItems.isNotEmpty ? dropdownItems.first.value : null;
return [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Card Number*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -738,7 +757,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -748,7 +767,6 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
@ -756,21 +774,17 @@ class _ForexScreenState extends State<ForexScreen> {
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Currency*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -787,36 +801,34 @@ class _ForexScreenState extends State<ForexScreen> {
decoration: InputDecoration(
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(
horizontal: 10), // Proper padding
horizontal: 10,
), // Proper padding
),
onChanged: purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
onChanged:
purposeList.isNotEmpty
? (newValue) {
setState(() {
selectedPurpose = newValue;
});
}
: null,
items: dropdownItems,
),
),
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Card*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -841,21 +853,17 @@ class _ForexScreenState extends State<ForexScreen> {
),
],
),
if (isDesktop)
Spacer()
else
SizedBox(
height: 8,
),
if (isDesktop) Spacer() else SizedBox(height: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Cash*",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldItnerarySubWrapper(
@ -863,7 +871,7 @@ class _ForexScreenState extends State<ForexScreen> {
isDesktop: isDesktop,
child: SizedBox(
height: 40,
child: TextField(
child: TextField(
focusNode: _fromFocusNode,
controller: _fromController,
style: const TextStyle(fontSize: 12),
@ -873,16 +881,12 @@ class _ForexScreenState extends State<ForexScreen> {
floatingLabelBehavior: FloatingLabelBehavior.never,
border: InputBorder.none,
contentPadding: EdgeInsets.symmetric(vertical: 16),
),
),
),
),
],
),
];
}
@ -894,17 +898,19 @@ class _ForexScreenState extends State<ForexScreen> {
Text(
"Delivery Location",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74)),
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
SizedBox(height: 5),
CustomTextFieldWrapper(
isFocused: _commentsFocus, // Dropdown doesn't use focus
isDesktop: isDesktop,
width: isDesktop
? MediaQuery.of(context).size.width * 0.4
: MediaQuery.of(context).size.width * 0.66,
width:
isDesktop
? MediaQuery.of(context).size.width * 0.4
: MediaQuery.of(context).size.width * 0.66,
child: TextField(
focusNode: _commentsFocusNode,
controller: _commentsController,
@ -921,7 +927,7 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
],
)
),
];
}
@ -944,10 +950,14 @@ class _ForexScreenState extends State<ForexScreen> {
),
Text(
"Check If You Don't Have a forex Account",
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFF575A74)),
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: Color(0xFF575A74),
),
),
],
)
),
];
}
@ -960,9 +970,7 @@ class _ForexScreenState extends State<ForexScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.grey[400], // Light grey color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
@ -971,7 +979,6 @@ class _ForexScreenState extends State<ForexScreen> {
),
),
SizedBox(width: 10), // Space between buttons
// Save Changes Button
ElevatedButton(
onPressed: () {
@ -979,9 +986,7 @@ class _ForexScreenState extends State<ForexScreen> {
},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue, // Primary color for save
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
child: Text(
@ -991,4 +996,4 @@ class _ForexScreenState extends State<ForexScreen> {
),
];
}
}
}

View File

@ -348,6 +348,7 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _numPassengerFocusNode,
controller: _numPassengerController,
style: const TextStyle(fontSize: 12),
keyboardType: TextInputType.numberWithOptions(decimal: true),
inputFormatters: [
@ -850,6 +851,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _destinationFocusNode,
controller: _destinationController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "Destination",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -888,6 +892,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _locationFocusNode,
controller: _locationController,
style: const TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: const InputDecoration(
labelText: "Pickup Location",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -932,6 +939,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _dateFocusNode,
controller: _dateController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -985,6 +997,11 @@ class _TaxiScreenState extends State<TaxiScreen> {
child: TextField(
focusNode: _timeFocusNode,
controller: _timeController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
readOnly: true,
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
@ -1045,6 +1062,9 @@ class _TaxiScreenState extends State<TaxiScreen> {
focusNode: _commentsFocusNode,
controller: _taxiCommentsController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -466,6 +467,9 @@ class _TrainScreenState extends State<TrainScreen> {
focusNode: _trainNoFocusNode,
controller: _trainNoController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
decoration: InputDecoration(
labelText: "Train number",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -1356,6 +1360,9 @@ class _TrainScreenState extends State<TrainScreen> {
// maxLines: 6,
// keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
decoration: InputDecoration(
labelText: "Comments",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),

View File

@ -1,5 +1,6 @@
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart';
import 'package:responsive_builder/responsive_builder.dart';
@ -163,9 +164,9 @@ class _VisaScreenState extends State<VisaScreen> {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
});
}
@ -549,7 +550,7 @@ class _VisaScreenState extends State<VisaScreen> {
width:
isDesktop
? MediaQuery.of(context).size.width * 0.34
: null,//MediaQuery.of(context).size.width * 0.66,
: null, //MediaQuery.of(context).size.width * 0.66,
child: SizedBox(
height: 40,
child: Focus(
@ -566,104 +567,108 @@ class _VisaScreenState extends State<VisaScreen> {
// Request focus when user taps
_countryFocusNode?.requestFocus();
},
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
print("contryItem - $item");
child: DropdownSearch<String>(
selectedItem: countryMap[selectedCountry],
popupProps: PopupProps.menu(
showSearchBox: true,
fit: FlexFit.loose,
constraints: BoxConstraints(maxHeight: 200),
menuProps: const MenuProps(backgroundColor: Colors.white),
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 Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Padding(
padding: const EdgeInsets.only(right: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
countryName,
style: GoogleFonts.poppins(fontSize: 11.5),
final match = RegExp(
r'^(.*)\s\((.*)\)$',
).firstMatch(item);
final countryName = match?.group(1) ?? '';
final countryCode = match?.group(2) ?? '';
return Container(
color: Colors.white,
padding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 6,
),
child: Padding(
padding: const EdgeInsets.only(right: 1.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,
),
),
],
),
Text(
countryCode,
style: GoogleFonts.poppins(
fontSize: 11.5,
color: Colors.grey,
),
),
],
),
),
);
},
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search ...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor!
: Colors.white,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select ",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
hintText: "Search ...",
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
),
onChanged: (String? newValue) {
setState(() {
selectedCountry =
countryMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
});
},
),),),
items: countryMap.values.toList(),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor!
: Colors.white,
width: 1,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_countryFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 1,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 1),
),
contentPadding: EdgeInsets.symmetric(horizontal: 10),
),
),
dropdownBuilder:
(context, selectedItem) => Align(
alignment: Alignment.centerLeft,
child: Text(
selectedItem ?? "Select ",
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
),
onChanged: (String? newValue) {
setState(() {
selectedCountry =
countryMap.entries
.firstWhere((entry) => entry.value == newValue)
.key;
});
},
),
),
),
),
),
if (errorMessages["country_code"] != null) ...[
@ -729,115 +734,120 @@ class _VisaScreenState extends State<VisaScreen> {
child: SizedBox(
height: 40,
width: double.infinity,
child: Focus(
focusNode: _tripTypeFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_tripTypeFocused = hasFocus;
});
child: Focus(
focusNode: _tripTypeFocusNode,
onFocusChange: (hasFocus) {
setState(() {
_tripTypeFocused = hasFocus;
});
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_tripTypeFocusNode?.requestFocus();
},
child: GestureDetector(
//
onTap: () {
// Request focus when user taps
_tripTypeFocusNode?.requestFocus();
},
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedPurpose,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
child: DropdownSearch<Map<String, dynamic>>(
items: purposeList.cast<Map<String, dynamic>>(),
selectedItem: purposeList.firstWhere(
(item) => item['dropdown_key'] == selectedPurpose,
orElse: () => {},
),
itemAsString: (item) => item['dropdown_value'] ?? '',
popupProps: PopupProps.menu(
showSearchBox: false,
fit: FlexFit.loose,
menuProps: const MenuProps(backgroundColor: Colors.white),
itemBuilder: (context, item, isSelected) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
vertical: 5,
),
child: Text(
item['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: layoutColor,
width: 0.5,
),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
),
child: Text(
item['dropdown_value'] ?? '',
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
),
);
},
),
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
// border: InputBorder.none,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5),
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor!
: Colors.white,
width: 0.5,
),
),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color:
(_tripTypeFocused ?? false)
? layoutColor
: Colors.white,
// : const Color(0xFFD6D5E6),
width: 0.5,
// const Color(0xFFD6D5E6),
),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: layoutColor, width: 0.5),
),
contentPadding: EdgeInsets.symmetric(
horizontal: 10,
vertical: 10,
),
);
},
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
// value: selectedPurpose,
// style: TextStyle(fontSize: 12),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding:
// EdgeInsets.symmetric(horizontal: 10), // Proper padding
// ),
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) {
setState(() {
selectedPurpose = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedPurpose}");
});
}
: null,
),
),
dropdownBuilder: (context, selectedItem) {
if (selectedItem == null || selectedItem.isEmpty) {
return Text(
"Select ",
style: GoogleFonts.poppins(
color: Colors.grey,
fontSize: 13,
),
);
}
return Text(
selectedItem['dropdown_value'] ?? '',
style: GoogleFonts.poppins(
fontSize: 12,
color: Colors.black,
),
);
},
// focusNode: _tripTypeFocusNode, // Assign the correct focus node
// value: selectedPurpose,
// style: TextStyle(fontSize: 12),
// decoration: InputDecoration(
// border: InputBorder.none,
// contentPadding:
// EdgeInsets.symmetric(horizontal: 10), // Proper padding
// ),
onChanged:
purposeList.isNotEmpty
? (Map<String, dynamic>? newValue) {
setState(() {
selectedPurpose = newValue?['dropdown_key'];
print("Selected Purpose: ${selectedPurpose}");
});
}
: null,
),),),
),
),
),
if (errorMessages["type_of_visa"] != null) ...[
@ -933,6 +943,9 @@ class _VisaScreenState extends State<VisaScreen> {
child: TextField(
focusNode: _commentsFocusNode,
controller: _visaCommentsController,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12),
decoration: InputDecoration(
labelText: "Comments",

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom;
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
@ -636,6 +637,9 @@ class TemplateState extends State<Template> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["subjectFocusNode"],
controller: controllers["subject"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
// _clearError("local_id_num");
},

View File

@ -4,6 +4,7 @@ import 'dart:async';
import 'dart:io' as io show Directory, File;
import 'package:delta_to_html/delta_to_html.dart';
import 'package:flutter/cupertino.dart' as dom;
import 'package:flutter/services.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
import 'package:flutter/material.dart';
import 'package:flutter_quill/flutter_quill.dart' hide Text;
@ -754,6 +755,9 @@ class TemplateForexState extends State<TemplateForex> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["subjectFocusNode"],
controller: controllers["subject"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
// _clearError("local_id_num");
},

View File

@ -1,5 +1,6 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/services/apiService.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -332,6 +333,9 @@ class _MailSettingState extends State<MailSetting> {
height: 40,
child: TextField(
// focusNode: _destinationFocusNode,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["userNameFocusNode"],
controller: controllers["userName"],
onChanged: (value) {
@ -577,6 +581,7 @@ class _MailSettingState extends State<MailSetting> {
child: TextField(
// focusNode: _destinationFocusNode,
focusNode: focusNodes["portFocusNode"],
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
controller: controllers["port"],
onChanged: (value) {
_clearError("mail_port");

View File

@ -1,7 +1,9 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:frontend/Screens/organization/mailSettings.dart';
import 'package:frontend/Screens/organization/themeColor.dart';
import 'package:go_router/go_router.dart';
@ -652,6 +654,45 @@ class _OrgSetUpState extends State<OrgSetUp> {
Future<void> _pickImage() async {
final picker = ImagePicker();
final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery,
// For web: allow only specific file types
// This only works on web
preferredCameraDevice: CameraDevice.rear, // optional
);
if (pickedFile != null) {
// Check the file extension manually
final allowedExtensions = ['jpg', 'jpeg', 'png'];
final fileExtension = pickedFile.name.split('.').last.toLowerCase();
if (!allowedExtensions.contains(fileExtension)) {
print('❌ Invalid file type. Please select a JPG or PNG image.');
return;
}
if (kIsWeb) {
try {
final bytes = await pickedFile.readAsBytes();
print('✅ Image loaded, size: ${bytes.length} bytes');
setState(() {
_imageBytes = bytes;
});
} catch (e) {
print('❌ Error reading image bytes: $e');
}
} else {
// Handle mobile image if needed
print('✅ Image picked: ${pickedFile.path}');
}
} else {
print('⚠️ Image picking canceled.');
}
}
Future<void> _pickImage2() async {
final picker = ImagePicker();
final XFile? pickedFile = await picker.pickImage(
source: ImageSource.gallery,
);
@ -772,7 +813,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
Expanded(
child: TextFormField(
controller: _orgNameController,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: GoogleFonts.poppins(
fontSize: 16,
color: Color(0xFF114D8B),
@ -787,6 +832,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
FloatingLabelBehavior.never,
border: InputBorder.none,
isDense: true,
// contentPadding:
// EdgeInsets.symmetric(vertical: 14),
),
@ -794,50 +840,74 @@ class _OrgSetUpState extends State<OrgSetUp> {
),
),
Spacer(),
GestureDetector(
onTap: _pickImage,
Column(
children: [
GestureDetector(
onTap: _pickImage,
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
fit: BoxFit.contain,
),
)
: selectedOrg?['logo'] != null
? ClipRect(
child: Image.network(
selectedOrg!['logo'],
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
// 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),
),
child:
_imageBytes != null
? ClipOval(
child: Image.memory(
_imageBytes!,
// width: 50,
// height: 50,
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
fit: BoxFit.contain,
),
)
: selectedOrg?['logo'] != null
? ClipRect(
child: Image.network(
selectedOrg!['logo'],
width:
responsiveLogoWidth, // Use responsive width
height: responsiveLogoHeight,
// 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,
),
),
),
SizedBox(
// width: 200,
child: Text(
"* Allow types jpg, jpeg, png",
// maxLines: 2,
// softWrap: true,
style: GoogleFonts.poppins(
fontSize: 9,
fontWeight: FontWeight.w400,
color: Colors.grey,
),
),
),
],
),
],
),

View File

@ -865,6 +865,7 @@ class ForexDataState extends State<ForexData> {
focusNode: focusNodes["perdiemAmountFocusNode"],
controller: controllers["perdiemAmount"],
style: const TextStyle(fontSize: 12),
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: const InputDecoration(
labelText: "Perdiem Amount",
labelStyle: TextStyle(fontSize: 11, color: Colors.grey),

View File

@ -3222,6 +3222,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
focusNode: focusNodes["so_numberFocusNode"],
controller: _soNumberController,
style: TextStyle(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
decoration: InputDecoration(
labelText: "SO Number",
labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
@ -3416,6 +3421,9 @@ class CreateNewPlansState extends State<CreateNewPlan> {
TextField(
controller: _excepntldescriptionController,
maxLines: 3,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
decoration: InputDecoration(
hintText: "Enter reason...",
hintStyle: GoogleFonts.poppins(fontSize: 10),
@ -3510,6 +3518,11 @@ class CreateNewPlansState extends State<CreateNewPlan> {
child: SizedBox(
height: 55,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
focusNode: focusNodes["excepntldescriptionFocusNode"],
controller: _excepntldescriptionController,
maxLines: 2,
@ -3610,6 +3623,12 @@ class CreateNewPlansState extends State<CreateNewPlan> {
focusNode: focusNodes["descriptionFocusNode"],
controller: _descriptionController,
maxLines: 2,
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 12),
enabled: !widget.isViewMode,
@ -3743,6 +3762,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
color: Colors.black,
),
enabled: !widget.isViewMode,
decoration: InputDecoration(
labelText: "Trip Name *",
labelStyle: GoogleFonts.poppins(
@ -3765,7 +3785,7 @@ class CreateNewPlansState extends State<CreateNewPlan> {
keyboardType: TextInputType.text,
scrollPhysics: BouncingScrollPhysics(),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
),
),
@ -4278,19 +4298,36 @@ class CreateNewPlansState extends State<CreateNewPlan> {
selectedIstravelUser = isTraveller;
});
print("USer entered : $otherUserName $userId $isTraveller");
print('---UserSelectionDialog');
// NOTE : Traveller use same trip token for self user,
// Trip Token changed for Other Employee -Selects userId should pass
if (isTraveller) {
await apiService.handleTripWiseToken(
selfId!,
context,
); // since userId is for traveller
print('---TRAVELLER');
print('---TRAVELLER- $userId');
fetchUserDetails();
_selectedTripType = null;
getSelectedPlanFor();
fetchUsrDtlFromSelectedTripUser();
dynamicItineraryKey.currentState?.loadOrgSelectedAlServices();
dynamicItineraryKey.currentState?.updateSelectedServices();
// await apiService.handleTripWiseToken(
// // selfId!,
// userId,
// context,
// ); // since userId is for traveller
} else {
print('---NONTRAVELLER');
print('---NONTRAVELLER $userId');
await apiService.handleTripWiseToken(
userId,
context,
); // fallback to selfId
}
print('UserSelectionDialog-1');
getSelectedPlanFor();
print('UserSelectionDialog-2');
fetchUsrDtlFromSelectedTripUser();
dynamicItineraryKey.currentState?.loadOrgSelectedAlServices();

View File

@ -59,7 +59,7 @@ class _ListPlansState extends State<ListPlans> {
@override
void initState() {
super.initState();
print("LSIT PLan -1");
_checkAuthAndLoadData();
checkbackbutton();
@ -69,6 +69,7 @@ class _ListPlansState extends State<ListPlans> {
}
void checkbackbutton() async {
print("LSIT PLan -3");
roleUser = await getRoleUser();
print(roleUser);
if (roleUser == "User") {
@ -79,6 +80,14 @@ class _ListPlansState extends State<ListPlans> {
print("msUser - $msUser");
html.window.history.pushState(null, '', html.window.location.href);
print("locationLP - $location");
// if (location!.contains('/listPlan')) {
// // Do nothing or show "Press again to exit" toast
// print("Blocked back on /listPlan");
// } else {
// print("/listPlan ..");
// }
if (!msUser) {
_popStateListener = html.window.onPopState.listen((event) {
if (!_dialogShown && mounted) {
@ -99,6 +108,7 @@ class _ListPlansState extends State<ListPlans> {
}
void _showBackConfirmationDialog() {
print('List planstt');
if (!mounted) return;
_dialogShown = true;
@ -144,11 +154,12 @@ class _ListPlansState extends State<ListPlans> {
}
void _checkAuthAndLoadData() async {
print("LSIT PLan -2");
final String? token = await getToken(); // Your async function to get token
if (token == null || token.isEmpty) {
// Token doesn't exist → redirect to login
// apiService.logout(context);
context.go(
"/",
); // or use: router.go("/") if you're using `GoRouter` directly
@ -358,7 +369,7 @@ class _ListPlansState extends State<ListPlans> {
}
}
void deletePlan(String planId) async {
void deletePlan(String planId, userId) async {
// try {
// Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
// print("ViewAAA - $planData");
@ -377,6 +388,7 @@ class _ListPlansState extends State<ListPlans> {
try {
Map<String, dynamic> planData = await ApiService().getViewPlan(
planId,
userId,
context,
);
print("ViewAAA - $planData");
@ -1255,6 +1267,7 @@ class _ListPlansState extends State<ListPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),
@ -1601,6 +1614,7 @@ class _ListPlansState extends State<ListPlans> {
);
deletePlan(
plan.planId,
userId,
);
},
),

View File

@ -5,6 +5,7 @@ import 'dart:ui' as html;
import 'dart:async';
import 'dart:html' as html;
import 'dart:typed_data';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'dart:ui' as web;
@ -953,6 +954,9 @@ class _PolicyState extends State<Policy> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["policyFocusNode"],
controller: _policyController,
onChanged: (value) => _clearError("name"),

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:dropdown_search/dropdown_search.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -3798,6 +3799,11 @@ class PolicyCriteriaState extends State<PolicyCriteria> {
child: TextField(
style: GoogleFonts.poppins(fontSize: 12),
controller: costController[ServiceId],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
// enabled: !isViewMode,
onChanged: (value) {
printData();

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -311,6 +312,11 @@ class PurposeOfTravelDataState extends State<PurposeOfTravelData> {
child: TextField(
controller: controllers["dropdown_value"],
focusNode: focusNodes["dropdown_valueFocusNode"],
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
style: const TextStyle(fontSize: 12),
decoration: const InputDecoration(
labelText: "Name",

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:http/http.dart' as http;
@ -340,6 +341,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["first_name"],
focusNode: focusNodes["first_nameFocusNode"],
style: const TextStyle(fontSize: 12),
@ -385,6 +391,11 @@ class TravellerDataState extends State<TravellerData> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(
RegExp(r'[a-zA-Z0-9 _-]'),
),
],
controller: controllers["last_name"],
focusNode: focusNodes["last_nameFocusNode"],
style: const TextStyle(fontSize: 12),

View File

@ -815,6 +815,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: focusNodes["FnameFocusNode"],
controller: widget.controllers["Fname"],
enabled: !widget.isViewMode,
@ -869,6 +872,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: focusNodes["LnameFocusNode"],
controller: widget.controllers["Lname"],
@ -916,6 +922,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: focusNodes["CnameFocusNode"],
controller: widget.controllers["Cname"],

View File

@ -551,6 +551,9 @@ class OfficeDetailsState extends State<OfficeDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
focusNode: _employeeCodeFocusNode,
controller: widget.controllers["employeeCode"],
enabled: !widget.isViewMode,

View File

@ -861,6 +861,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
// focusNode: focusNodes["FnameFocusNode"],
focusNode: _fnameFocusNode, // 👈 Use it here
controller: widget.controllers["Fname"],
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
autofocus: true,
enabled: !widget.isViewMode,
onChanged: (value) {
@ -910,6 +913,9 @@ class PersonalDetailsState extends State<PersonalDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: TextStyle(fontSize: 12, color: Colors.black),
focusNode: _lnameFocusNode,
autofocus: true,

View File

@ -1221,6 +1221,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["FnameFocusNode"],
controller: controllers["Fname"],
enabled: !widget.isViewMode,
@ -1264,6 +1267,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["MnameFocusNode"],
controller: controllers["Mname"],
enabled: !widget.isViewMode,
@ -1310,6 +1316,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["LnameFocusNode"],
controller: controllers["Lname"],
@ -1548,6 +1557,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
focusNode: focusNodes["placeOfIssueFocusNode"],
controller: controllers["placeOfIssue"],
enabled: !widget.isViewMode,
@ -2339,6 +2351,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["local_id_num"],
enabled: !widget.isViewMode,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
onChanged: (value) {
_clearError("local_id_num");
},
@ -2476,6 +2491,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
height: 40,
child: TextField(
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
controller: controllers["full_name_as_id"],
enabled: !widget.isViewMode,
onChanged: (value) {
@ -2710,6 +2728,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
focusNode: focusNodes["d_meal_prefFocusNode"],
controller: controllers["d_meal_pref"],
@ -2755,6 +2776,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["d_additonal_Info"],
focusNode: focusNodes["d_additonal_InfoFocusNode"],
@ -2988,7 +3012,11 @@ class TravellerDetailsState extends State<TravellerDetails> {
isDesktop: widget.isDesktop,
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["i_meal_pref"],
focusNode: focusNodes["i_meal_prefFocusNode"],
@ -3034,6 +3062,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: controllers["i_additonal_Info"],
focusNode: focusNodes["i_additonal_InfoFocusNode"],
@ -3629,6 +3660,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9_-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: entry["controller_flier_number"],
enabled: !widget.isViewMode,
@ -3893,6 +3927,9 @@ class TravellerDetailsState extends State<TravellerDetails> {
child: SizedBox(
height: 40,
child: TextField(
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9 _-]')),
],
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
controller: entry["controller_membership"],
enabled: !widget.isViewMode,

View File

@ -1,8 +1,11 @@
import 'dart:convert';
import 'dart:io';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:frontend/config/apiUrl.dart';
import 'package:go_router/go_router.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:image_picker/image_picker.dart';
import 'package:shared_preferences/shared_preferences.dart'; // don't forget
import '../services/apiService.dart';
import '../utils/auth_utils.dart';
@ -37,6 +40,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
late TabSelection selectedTab;
final ImagePicker _picker = ImagePicker();
String? token;
Map<String, dynamic>? userData;
Map<String, dynamic>? fetchedUserData;
@ -48,6 +53,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
Color? layoutColor = Colors.white10;
Color? bodyColor;
File? _pickedImageFile;
String? _errorMessage;
void initState() {
super.initState();
// initializeData();
@ -104,6 +112,14 @@ class _CustomAppBarState extends State<CustomAppBar> {
return prefs.getString("auth_token");
}
bool isValidImageUrl(String? url) {
if (url == null) return false;
final lowerUrl = url.toLowerCase();
return lowerUrl.endsWith('.jpg') ||
lowerUrl.endsWith('.jpeg') ||
lowerUrl.endsWith('.png');
}
Future<Map<String, dynamic>?> getUserData() async {
final prefs = await SharedPreferences.getInstance();
final String? userDataString = prefs.getString('user_data');

View File

@ -84,7 +84,7 @@ final GoRouter router = GoRouter(
// );
},
routes: [
GoRoute(path: '/home', builder: (context, state) => HomePage()),
// GoRoute(path: '/home', builder: (context, state) => HomePage()),
GoRoute(
path: '/listAllPlan',
builder: (context, state) => ListAllPlans(),

View File

@ -36,26 +36,31 @@ class OrganizationSettingState extends State<OrganizationSetting> {
// String? bodyStringColor = await getBodyColor();
roleUser = await getRoleUser();
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
if (roleUser == 'Org Admin' || roleUser == 'Travel Admin') {
setState(() {
layoutColor =
layoutString != null
? Color(int.parse(layoutString))
: Colors.redAccent;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
secondColor =
layoutString != null
? Color(int.parse(secondString!))
: Colors.orange;
thridColor =
layoutString != null
? Color(int.parse(thridString!))
: Colors.orangeAccent;
// bodyColor =
// bodyStringColor != null
// ? Color(int.parse(bodyStringColor))
// : Colors.white;
});
} else {
apiService.logout(context);
}
}
@override

View File

@ -743,9 +743,11 @@ class ApiService {
Future<Map<String, dynamic>> getViewPlan(
String planId,
userId,
BuildContext context,
) async {
final String apiUrldata = '$apiUrl/api/plans/cancle_plan?plan_id=$planId';
final String apiUrldata =
'$apiUrl/api/plans/cancle_plan?plan_id=$planId&updated_by=$userId';
// final String apiUrldata = '$apiUrl/api/plans/find/$planId';
print("API URL: $apiUrldata");