Page Shaking
This commit is contained in:
parent
b88973d43c
commit
3e3ef56694
@ -13,6 +13,7 @@ import 'package:shared_preferences/shared_preferences.dart';
|
|||||||
|
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
import '../../routes/custom_drawer.dart';
|
import '../../routes/custom_drawer.dart';
|
||||||
|
import '../../routes/mainLayout.dart';
|
||||||
import '../../services/apiService.dart';
|
import '../../services/apiService.dart';
|
||||||
import '../../utils/auth_utils.dart';
|
import '../../utils/auth_utils.dart';
|
||||||
import '../../utils/pagination.dart';
|
import '../../utils/pagination.dart';
|
||||||
@ -69,12 +70,15 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
print("allPlans before filtering: $allPlans");
|
print("allPlans before filtering: $allPlans");
|
||||||
final lowerQuery = query.toLowerCase();
|
final lowerQuery = query.toLowerCase();
|
||||||
setState(() {
|
setState(() {
|
||||||
filteredPlans = allPlans.where((plan) {
|
filteredPlans =
|
||||||
|
allPlans.where((plan) {
|
||||||
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
|
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ??
|
||||||
|
false) ||
|
||||||
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.travellerName?.toLowerCase().contains(lowerQuery) ??
|
||||||
|
false) ||
|
||||||
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
|
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||||
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
|
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
|
||||||
@ -88,11 +92,13 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
String? bodyStringColor = await getBodyColor();
|
String? bodyStringColor = await getBodyColor();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
layoutColor = layoutString != null
|
layoutColor =
|
||||||
|
layoutString != null
|
||||||
? Color(int.parse(layoutString))
|
? Color(int.parse(layoutString))
|
||||||
: Colors.redAccent;
|
: Colors.redAccent;
|
||||||
|
|
||||||
bodyColor = bodyStringColor != null
|
bodyColor =
|
||||||
|
bodyStringColor != null
|
||||||
? Color(int.parse(bodyStringColor))
|
? Color(int.parse(bodyStringColor))
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
});
|
});
|
||||||
@ -245,8 +251,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void deletePlan(String planId) async {
|
void deletePlan(String planId) async {
|
||||||
bool confirmed =
|
bool confirmed = await apiService.showCancelConfirmationDialog(
|
||||||
await apiService.showCancelConfirmationDialog(context, layoutColor);
|
context,
|
||||||
|
layoutColor,
|
||||||
|
);
|
||||||
|
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
try {
|
try {
|
||||||
@ -263,35 +271,48 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
builder: (context, sizingInfo) {
|
||||||
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
return Scaffold(
|
return MainLayout(
|
||||||
backgroundColor: Color(0xFFf5f5f5),
|
isDesktop: isDesktop,
|
||||||
// backgroundColor: Color(0xFFFCFCFC),
|
|
||||||
|
|
||||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
|
||||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
|
||||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
|
||||||
drawer: CustomDrawer(isDesktop: false),
|
|
||||||
body: Padding(
|
|
||||||
padding: isDesktop
|
|
||||||
? EdgeInsets.symmetric(
|
|
||||||
horizontal: MediaQuery.of(context).size.width *
|
|
||||||
0.1, // 30% of screen width as horizontal padding
|
|
||||||
vertical: MediaQuery.of(context).size.height *
|
|
||||||
0, // 5% of screen height as vertical padding
|
|
||||||
)
|
|
||||||
: EdgeInsets.all(0),
|
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
Expanded(child: buildGroupListLayout(isDesktop))
|
Expanded(child: buildGroupListLayout(isDesktop)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
});
|
|
||||||
|
// return Scaffold(
|
||||||
|
// backgroundColor: Color(0xFFf5f5f5),
|
||||||
|
// // backgroundColor: Color(0xFFFCFCFC),
|
||||||
|
// appBar: CustomAppBar(isDesktop: isDesktop),
|
||||||
|
// drawer: CustomDrawer(isDesktop: false),
|
||||||
|
// body: Padding(
|
||||||
|
// padding:
|
||||||
|
// isDesktop
|
||||||
|
// ? EdgeInsets.symmetric(
|
||||||
|
// horizontal:
|
||||||
|
// MediaQuery.of(context).size.width *
|
||||||
|
// 0.1, // 30% of screen width as horizontal padding
|
||||||
|
// vertical:
|
||||||
|
// MediaQuery.of(context).size.height *
|
||||||
|
// 0, // 5% of screen height as vertical padding
|
||||||
|
// )
|
||||||
|
// : EdgeInsets.all(0),
|
||||||
|
// child: Row(
|
||||||
|
// children: [
|
||||||
|
// // if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
|
// Expanded(child: buildGroupListLayout(isDesktop)),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildGroupListLayout(bool isDesktop) {
|
Widget buildGroupListLayout(bool isDesktop) {
|
||||||
@ -322,8 +343,9 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
String _formatDate(String rawDate) {
|
String _formatDate(String rawDate) {
|
||||||
try {
|
try {
|
||||||
final dateTime = DateTime.parse(rawDate);
|
final dateTime = DateTime.parse(rawDate);
|
||||||
return DateFormat('dd, MMM yyyy HH:mm')
|
return DateFormat(
|
||||||
.format(dateTime); // 24-hour format
|
'dd, MMM yyyy HH:mm',
|
||||||
|
).format(dateTime); // 24-hour format
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return rawDate; // fallback if parsing fails
|
return rawDate; // fallback if parsing fails
|
||||||
}
|
}
|
||||||
@ -332,11 +354,13 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
return Container(
|
return Container(
|
||||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||||
height: isDesktop
|
height:
|
||||||
|
isDesktop
|
||||||
? MediaQuery.of(context).size.height * 0.98
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
: MediaQuery.of(context).size.height,
|
: MediaQuery.of(context).size.height,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: isDesktop
|
border:
|
||||||
|
isDesktop
|
||||||
? Border.all(
|
? Border.all(
|
||||||
width: 2,
|
width: 2,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@ -382,9 +406,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(width: 1),
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
Spacer(),
|
Spacer(),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
Container(
|
Container(
|
||||||
@ -395,8 +417,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
onChanged: filterPlans,
|
onChanged: filterPlans,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search...",
|
hintText: "Search...",
|
||||||
hintStyle:
|
hintStyle: TextStyle(
|
||||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
fontSize: 12,
|
||||||
|
color: Color(0xFF9E9DBD),
|
||||||
|
),
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
@ -408,22 +432,23 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade200, width: 0.5),
|
color: Colors.grey.shade200,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade300, width: 1),
|
color: Colors.grey.shade300,
|
||||||
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: GoogleFonts.poppins(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
),
|
||||||
|
style: GoogleFonts.poppins(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// SizedBox(width: 16),
|
// SizedBox(width: 16),
|
||||||
|
|
||||||
Spacer(),
|
Spacer(),
|
||||||
// ElevatedButton(
|
// ElevatedButton(
|
||||||
// style: ElevatedButton.styleFrom(
|
// style: ElevatedButton.styleFrom(
|
||||||
@ -521,8 +546,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
onChanged: filterPlans,
|
onChanged: filterPlans,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search...",
|
hintText: "Search...",
|
||||||
hintStyle:
|
hintStyle: TextStyle(
|
||||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
fontSize: 12,
|
||||||
|
color: Color(0xFF9E9DBD),
|
||||||
|
),
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.search,
|
Icons.search,
|
||||||
color: Color(0xFF9E9DBD),
|
color: Color(0xFF9E9DBD),
|
||||||
@ -534,17 +561,19 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade200, width: 0.5),
|
color: Colors.grey.shade200,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: BorderSide(
|
borderSide: BorderSide(
|
||||||
color: Colors.grey.shade300, width: 1),
|
color: Colors.grey.shade300,
|
||||||
|
width: 1,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
style: GoogleFonts.poppins(
|
|
||||||
fontSize: 12,
|
|
||||||
),
|
),
|
||||||
|
style: GoogleFonts.poppins(fontSize: 12),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -581,14 +610,17 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 20,
|
fontSize: 20,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Colors.black54),
|
color: Colors.black54,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 10),
|
const SizedBox(height: 10),
|
||||||
Text(
|
Text(
|
||||||
"Please Create Trip",
|
"Please Create Trip",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12, color: Colors.grey),
|
fontSize: 12,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -604,10 +636,13 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
List<Plan> plans =
|
List<Plan> plans =
|
||||||
searchController.text.isEmpty ? allPlans : filteredPlans;
|
searchController.text.isEmpty ? allPlans : filteredPlans;
|
||||||
|
|
||||||
plans.sort((a, b) =>
|
plans.sort(
|
||||||
int.parse(b.planId).compareTo(int.parse(a.planId)));
|
(a, b) =>
|
||||||
|
int.parse(b.planId).compareTo(int.parse(a.planId)),
|
||||||
|
);
|
||||||
|
|
||||||
List<Plan> paginatedPlans = plans
|
List<Plan> paginatedPlans =
|
||||||
|
plans
|
||||||
.skip(currentPage * itemsPerPage)
|
.skip(currentPage * itemsPerPage)
|
||||||
.take(itemsPerPage)
|
.take(itemsPerPage)
|
||||||
.toList();
|
.toList();
|
||||||
@ -623,112 +658,169 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||||
border: TableBorder(
|
border: TableBorder(
|
||||||
horizontalInside: BorderSide(
|
horizontalInside: BorderSide(
|
||||||
width: 0.5, color: Colors.grey.shade200),
|
width: 0.5,
|
||||||
|
color: Colors.grey.shade200,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
columns: [
|
columns: [
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Trip ID',
|
'Trip ID',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Trip Name',
|
'Trip Name',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Emp Code',
|
'Emp Code',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Traveller',
|
'Traveller',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Trip Type',
|
'Trip Type',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Created On',
|
'Created On',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Status',
|
'Status',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataColumn(
|
DataColumn(
|
||||||
label: Text(
|
label: Text(
|
||||||
'Actions',
|
'Actions',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 13, fontWeight: FontWeight.w600),
|
fontSize: 13,
|
||||||
)),
|
fontWeight: FontWeight.w600,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
rows: paginatedPlans.map((plan) {
|
rows:
|
||||||
return DataRow(cells: [
|
paginatedPlans.map((plan) {
|
||||||
DataCell(Text(plan.planId,
|
return DataRow(
|
||||||
|
cells: [
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
|
plan.planId,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
))),
|
),
|
||||||
DataCell(Text(plan.tripTitle,
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
|
plan.tripTitle,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
),
|
),
|
||||||
softWrap: true,
|
softWrap: true,
|
||||||
overflow: TextOverflow.ellipsis)),
|
overflow: TextOverflow.ellipsis,
|
||||||
DataCell(Text(plan.employeeCode ?? " - ",
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
|
plan.employeeCode ?? " - ",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
))),
|
),
|
||||||
DataCell(Text(
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
plan.userName.isNotEmpty
|
plan.userName.isNotEmpty
|
||||||
? plan.userName
|
? plan.userName
|
||||||
: plan.travellerName,
|
: plan.travellerName,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
))),
|
),
|
||||||
DataCell(Text(plan.tripType,
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
|
plan.tripType,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
))),
|
),
|
||||||
DataCell(Text(_formatDate(plan.createdOn),
|
),
|
||||||
|
),
|
||||||
|
DataCell(
|
||||||
|
Text(
|
||||||
|
_formatDate(plan.createdOn),
|
||||||
// plan.createdOn,
|
// plan.createdOn,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
))),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
DataCell(
|
DataCell(
|
||||||
Container(
|
Container(
|
||||||
width: double
|
width:
|
||||||
|
double
|
||||||
.infinity, // Set your desired fixed size (equal width and height)
|
.infinity, // Set your desired fixed size (equal width and height)
|
||||||
height: 25,
|
height: 25,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: getStatusColor(plan.statusValue),
|
color: getStatusColor(
|
||||||
borderRadius: BorderRadius.circular(10),
|
plan.statusValue,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
10,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
plan.statusValue,
|
plan.statusValue,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color:
|
color: getStatusTextColor(
|
||||||
getStatusTextColor(plan.statusValue),
|
plan.statusValue,
|
||||||
|
),
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
@ -748,84 +840,130 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
color: Color(0xFF475569),
|
color: Color(0xFF475569),
|
||||||
size: 14,
|
size: 14,
|
||||||
),
|
),
|
||||||
itemBuilder: (context) => [
|
itemBuilder:
|
||||||
|
(context) => [
|
||||||
CustomPopupMenuEntry(
|
CustomPopupMenuEntry(
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding:
|
||||||
horizontal: 8, vertical: 8),
|
EdgeInsets.symmetric(
|
||||||
|
horizontal: 8,
|
||||||
|
vertical: 8,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize:
|
||||||
|
MainAxisSize.min,
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.center,
|
MainAxisAlignment
|
||||||
|
.center,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.remove_red_eye,
|
Icons
|
||||||
color: Color(0xFF475569),
|
.remove_red_eye,
|
||||||
size: 18),
|
color: Color(
|
||||||
tooltip: 'View Trips',
|
0xFF475569,
|
||||||
|
),
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
tooltip:
|
||||||
|
'View Trips',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(
|
Navigator.pop(
|
||||||
context); // Close popup manually
|
context,
|
||||||
|
); // Close popup manually
|
||||||
ApiService.viewPlan(
|
ApiService.viewPlan(
|
||||||
context, plan.planId,
|
context,
|
||||||
isViewMode: true);
|
plan.planId,
|
||||||
|
isViewMode:
|
||||||
|
true,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Image.asset(
|
icon: Image.asset(
|
||||||
'assets/images/IconsImg/edit.png',
|
'assets/images/IconsImg/edit.png',
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 15),
|
height: 15,
|
||||||
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(
|
||||||
|
context,
|
||||||
|
);
|
||||||
ApiService.viewPlan(
|
ApiService.viewPlan(
|
||||||
context, plan.planId,
|
context,
|
||||||
isViewMode: false);
|
plan.planId,
|
||||||
|
isViewMode:
|
||||||
|
false,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
Icons.cancel_rounded,
|
Icons
|
||||||
size: 18),
|
.cancel_rounded,
|
||||||
tooltip: 'Cancellation Trips',
|
size: 18,
|
||||||
|
),
|
||||||
|
tooltip:
|
||||||
|
'Cancellation Trips',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(
|
||||||
deletePlan(plan.planId);
|
context,
|
||||||
|
);
|
||||||
|
deletePlan(
|
||||||
|
plan.planId,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.download,
|
icon: Icon(
|
||||||
color: Color(0xFF114D8B),
|
Icons.download,
|
||||||
size: 18),
|
color: Color(
|
||||||
tooltip: 'Download Trips Detials',
|
0xFF114D8B,
|
||||||
|
),
|
||||||
|
size: 18,
|
||||||
|
),
|
||||||
|
tooltip:
|
||||||
|
'Download Trips Detials',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(
|
||||||
apiService.getPdfDownload(
|
context,
|
||||||
plan.planId);
|
);
|
||||||
|
apiService
|
||||||
|
.getPdfDownload(
|
||||||
|
plan.planId,
|
||||||
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.comment,
|
Icons.comment,
|
||||||
color: Color(0xFF475569),
|
color: Color(
|
||||||
|
0xFF475569,
|
||||||
|
),
|
||||||
size: 11,
|
size: 11,
|
||||||
),
|
),
|
||||||
tooltip: 'Trips Comments',
|
tooltip:
|
||||||
|
'Trips Comments',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context:
|
||||||
builder: (context) =>
|
context,
|
||||||
CommentModalList(
|
builder:
|
||||||
|
(
|
||||||
|
context,
|
||||||
|
) => CommentModalList(
|
||||||
// planId: plan.planId,
|
// planId: plan.planId,
|
||||||
planId: plan
|
planId:
|
||||||
.planId
|
plan.planId
|
||||||
.toString(),
|
.toString(),
|
||||||
layoutColorForUser:
|
layoutColorForUser:
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
role: "Admin"),
|
role:
|
||||||
|
"Admin",
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -835,7 +973,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]);
|
],
|
||||||
|
);
|
||||||
}).toList(),
|
}).toList(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -849,8 +988,10 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
final plan = paginatedPlans[index];
|
final plan = paginatedPlans[index];
|
||||||
return Card(
|
return Card(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
margin:
|
margin: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
horizontal: 12,
|
||||||
|
vertical: 6,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
@ -875,18 +1016,23 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: 8, vertical: 4),
|
horizontal: 8,
|
||||||
|
vertical: 4,
|
||||||
|
),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: getStatusColor(
|
color: getStatusColor(
|
||||||
plan.statusValue),
|
plan.statusValue,
|
||||||
borderRadius:
|
),
|
||||||
BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(
|
||||||
|
8,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
plan.statusValue,
|
plan.statusValue,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: getStatusTextColor(
|
color: getStatusTextColor(
|
||||||
plan.statusValue),
|
plan.statusValue,
|
||||||
|
),
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
),
|
),
|
||||||
@ -915,11 +1061,14 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(' ${plan.tripTitle}',
|
Text(
|
||||||
|
' ${plan.tripTitle}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -934,24 +1083,28 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(' ${plan.tripType}',
|
Text(
|
||||||
|
' ${plan.tripType}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
color: Colors.black87,
|
color: Colors.black87,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment:
|
crossAxisAlignment:
|
||||||
CrossAxisAlignment.start,
|
CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text('${_formatDate(plan.createdOn)}',
|
Text(
|
||||||
|
'${_formatDate(plan.createdOn)}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
color: Colors.black87,
|
color: Colors.black87,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -971,7 +1124,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
color: Colors.black87),
|
color: Colors.black87,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -985,7 +1139,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
fontFamily: "Inter",
|
fontFamily: "Inter",
|
||||||
color: Colors.black87),
|
color: Colors.black87,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -1005,14 +1160,17 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: isDesktop
|
child:
|
||||||
|
isDesktop
|
||||||
? (searchController.text.isNotEmpty &&
|
? (searchController.text.isNotEmpty &&
|
||||||
filteredPlans.isEmpty
|
filteredPlans.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"No matches found",
|
"No matches found",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14, color: Colors.grey),
|
fontSize: 14,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: SingleChildScrollView(
|
: SingleChildScrollView(
|
||||||
@ -1025,7 +1183,9 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
"No matches found",
|
"No matches found",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14, color: Colors.grey),
|
fontSize: 14,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
: buildMobileCardView(paginatedPlans)),
|
: buildMobileCardView(paginatedPlans)),
|
||||||
@ -1058,7 +1218,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Future<dynamic> showApprovalDialog(
|
Future<dynamic> showApprovalDialog(
|
||||||
BuildContext context, Color layoutColor) async {
|
BuildContext context,
|
||||||
|
Color layoutColor,
|
||||||
|
) async {
|
||||||
String selectedAction = ""; // "", "accept", "reject"
|
String selectedAction = ""; // "", "accept", "reject"
|
||||||
String remarks = "";
|
String remarks = "";
|
||||||
|
|
||||||
@ -24,13 +26,12 @@ Future<dynamic> showApprovalDialog(
|
|||||||
Text(
|
Text(
|
||||||
"To Approve or Reject Trip",
|
"To Approve or Reject Trip",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontFamily: "Inter", fontWeight: FontWeight.w500),
|
fontFamily: "Inter",
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(
|
icon: const Icon(Icons.close, size: 15),
|
||||||
Icons.close,
|
|
||||||
size: 15,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pop(context, null); // Close the dialog
|
Navigator.pop(context, null); // Close the dialog
|
||||||
},
|
},
|
||||||
@ -45,10 +46,12 @@ Future<dynamic> showApprovalDialog(
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: selectedAction == "accept"
|
backgroundColor:
|
||||||
? layoutColor
|
selectedAction == "accept"
|
||||||
|
? Colors.green
|
||||||
: Colors.grey.shade200,
|
: Colors.grey.shade200,
|
||||||
foregroundColor: selectedAction == "accept"
|
foregroundColor:
|
||||||
|
selectedAction == "accept"
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -68,10 +71,12 @@ Future<dynamic> showApprovalDialog(
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: selectedAction == "reject"
|
backgroundColor:
|
||||||
|
selectedAction == "reject"
|
||||||
? Colors.redAccent
|
? Colors.redAccent
|
||||||
: Colors.grey.shade200,
|
: Colors.grey.shade200,
|
||||||
foregroundColor: selectedAction == "reject"
|
foregroundColor:
|
||||||
|
selectedAction == "reject"
|
||||||
? Colors.white
|
? Colors.white
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
@ -122,12 +127,16 @@ Future<dynamic> showApprovalDialog(
|
|||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide: const BorderSide(
|
borderSide: const BorderSide(
|
||||||
color: Colors.blueGrey, width: 0.5),
|
color: Colors.blueGrey,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
borderSide:
|
borderSide: BorderSide(
|
||||||
BorderSide(color: Colors.blueGrey, width: 0.5),
|
color: Colors.blueGrey,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
@ -135,7 +144,7 @@ Future<dynamic> showApprovalDialog(
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
]
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
actionsAlignment: MainAxisAlignment.center,
|
actionsAlignment: MainAxisAlignment.center,
|
||||||
@ -187,14 +196,12 @@ Future<dynamic> showApprovalDialog(
|
|||||||
Future<bool?> showApproveDialog1(BuildContext context, Color layoutColor) {
|
Future<bool?> showApproveDialog1(BuildContext context, Color layoutColor) {
|
||||||
return showDialog<bool>(
|
return showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AlertDialog(
|
builder:
|
||||||
|
(context) => AlertDialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
title: const Text(
|
title: const Text(
|
||||||
"Confirm Approval",
|
"Confirm Approval",
|
||||||
style: TextStyle(
|
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
content: const Text("Are you sure you want to approve this plan?"),
|
content: const Text("Are you sure you want to approve this plan?"),
|
||||||
actions: [
|
actions: [
|
||||||
@ -231,14 +238,17 @@ Future<bool?> showApproveDialog1(BuildContext context, Color layoutColor) {
|
|||||||
|
|
||||||
/// Show confirm dialog for rejection with remarks input
|
/// Show confirm dialog for rejection with remarks input
|
||||||
Future<String?> showRejectDialog1(
|
Future<String?> showRejectDialog1(
|
||||||
BuildContext context, Color layoutColor) async {
|
BuildContext context,
|
||||||
|
Color layoutColor,
|
||||||
|
) async {
|
||||||
String remarks = "";
|
String remarks = "";
|
||||||
|
|
||||||
final confirmed = await showDialog<bool>(
|
final confirmed = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return StatefulBuilder(
|
return StatefulBuilder(
|
||||||
builder: (context, setState) => AlertDialog(
|
builder:
|
||||||
|
(context, setState) => AlertDialog(
|
||||||
backgroundColor: Colors.white,
|
backgroundColor: Colors.white,
|
||||||
contentPadding: const EdgeInsets.all(36),
|
contentPadding: const EdgeInsets.all(36),
|
||||||
// title: const Text("Confirm Rejection"),
|
// title: const Text("Confirm Rejection"),
|
||||||
@ -260,13 +270,20 @@ Future<String?> showRejectDialog1(
|
|||||||
hintStyle: TextStyle(
|
hintStyle: TextStyle(
|
||||||
fontSize: 10, // 👈 Set your desired font size here
|
fontSize: 10, // 👈 Set your desired font size here
|
||||||
color: Colors.grey,
|
color: Colors.grey,
|
||||||
fontFamily: "Inter", // optional if you want consistent font
|
fontFamily:
|
||||||
|
"Inter", // optional if you want consistent font
|
||||||
),
|
),
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),
|
borderSide: BorderSide(
|
||||||
|
color: Colors.blueGrey,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
enabledBorder: OutlineInputBorder(
|
enabledBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),
|
borderSide: BorderSide(
|
||||||
|
color: Colors.blueGrey,
|
||||||
|
width: 0.5,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderSide: BorderSide(color: Colors.grey, width: 1),
|
borderSide: BorderSide(color: Colors.grey, width: 1),
|
||||||
|
|||||||
@ -11,6 +11,8 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:url_launcher/url_launcher.dart';
|
import 'package:url_launcher/url_launcher.dart';
|
||||||
|
|
||||||
|
import '../../../services/apiService.dart';
|
||||||
|
|
||||||
class LoginWidget extends StatefulWidget {
|
class LoginWidget extends StatefulWidget {
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
final bool isTablet;
|
final bool isTablet;
|
||||||
@ -25,6 +27,9 @@ class LoginWidget extends StatefulWidget {
|
|||||||
enum LoginStep { login, forgotEmail, otpReset }
|
enum LoginStep { login, forgotEmail, otpReset }
|
||||||
|
|
||||||
class _LoginWidgetState extends State<LoginWidget> {
|
class _LoginWidgetState extends State<LoginWidget> {
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
bool _moved = false;
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
final TextEditingController _emailController = TextEditingController();
|
final TextEditingController _emailController = TextEditingController();
|
||||||
final TextEditingController _passwordController = TextEditingController();
|
final TextEditingController _passwordController = TextEditingController();
|
||||||
@ -39,6 +44,17 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
// 🔹 Login Step Enum and State Variable
|
// 🔹 Login Step Enum and State Variable
|
||||||
LoginStep _loginStep = LoginStep.login;
|
LoginStep _loginStep = LoginStep.login;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
Future.delayed(Duration(milliseconds: 300), () {
|
||||||
|
setState(() {
|
||||||
|
_moved = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_emailController.dispose();
|
_emailController.dispose();
|
||||||
@ -54,15 +70,18 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
final parts = token.split('.');
|
final parts = token.split('.');
|
||||||
if (parts.length != 3) throw Exception('Invalid token format');
|
if (parts.length != 3) throw Exception('Invalid token format');
|
||||||
|
|
||||||
final payload = json
|
final payload = json.decode(
|
||||||
.decode(utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))));
|
utf8.decode(base64Url.decode(base64Url.normalize(parts[1]))),
|
||||||
|
);
|
||||||
|
|
||||||
final userData = payload['data'];
|
final userData = payload['data'];
|
||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
await prefs.setString('auth_token', token);
|
await prefs.setString('auth_token', token);
|
||||||
await prefs.setString(
|
await prefs.setString(
|
||||||
'user_data', jsonEncode(userData)); // Store full user data
|
'user_data',
|
||||||
|
jsonEncode(userData),
|
||||||
|
); // Store full user data
|
||||||
|
|
||||||
if (userData != null) {
|
if (userData != null) {
|
||||||
final pref = await SharedPreferences.getInstance();
|
final pref = await SharedPreferences.getInstance();
|
||||||
@ -75,6 +94,8 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
print("userData11 - ${userData['role']}");
|
print("userData11 - ${userData['role']}");
|
||||||
print("userData12 - $userRole");
|
print("userData12 - $userRole");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apiService.getOrganizationData();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error decoding token: $e');
|
print('Error decoding token: $e');
|
||||||
}
|
}
|
||||||
@ -89,7 +110,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
Uri.parse(url),
|
Uri.parse(url),
|
||||||
headers: {
|
headers: {
|
||||||
'Content-Type': 'application/json',
|
'Content-Type': 'application/json',
|
||||||
'Accept': 'application/json'
|
'Accept': 'application/json',
|
||||||
},
|
},
|
||||||
body: jsonEncode({
|
body: jsonEncode({
|
||||||
'email': _emailController.text.trim(),
|
'email': _emailController.text.trim(),
|
||||||
@ -145,9 +166,9 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
// );
|
// );
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(
|
||||||
SnackBar(content: Text("Error: $e")),
|
context,
|
||||||
);
|
).showSnackBar(SnackBar(content: Text("Error: $e")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -175,19 +196,27 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
// _clearAllFields();
|
// _clearAllFields();
|
||||||
});
|
});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text("OTP sent to your email")),
|
SnackBar(
|
||||||
|
content: Text("OTP sent to your email"),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
print(response);
|
print(response);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content:
|
content: Text(
|
||||||
Text("${jsonDecode(response.body)['messages']['error']}")),
|
"${jsonDecode(response.body)['messages']['error']}",
|
||||||
|
),
|
||||||
|
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
.showSnackBar(SnackBar(content: Text("Error: $e")));
|
SnackBar(content: Text("Error: $e"), backgroundColor: Colors.red),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else if (!_isForgotPassword && _showOtpResetFields) {
|
} else if (!_isForgotPassword && _showOtpResetFields) {
|
||||||
print('22');
|
print('22');
|
||||||
@ -214,20 +243,32 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
_clearAllFields();
|
_clearAllFields();
|
||||||
});
|
});
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(content: Text("Password reset successfully")),
|
SnackBar(
|
||||||
|
content: Text("Password reset successfully"),
|
||||||
|
backgroundColor: Colors.green,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
print('23');
|
print('23');
|
||||||
print('otp wrong');
|
print('otp wrong');
|
||||||
|
final responseBody = json.decode(response.body);
|
||||||
|
final errorMessage =
|
||||||
|
responseBody['messages']?['error'] ?? 'An unknown error occurred';
|
||||||
|
print(errorMessage);
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text(
|
content: Text(
|
||||||
"Reset failed: ${jsonDecode(response.body)['message']}")),
|
"Reset failed: $errorMessage",
|
||||||
|
// "Reset failed: ${jsonDecode(response.body)['message']}",
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
ScaffoldMessenger.of(context)
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
.showSnackBar(SnackBar(content: Text("Error: $e")));
|
SnackBar(content: Text("Error: $e"), backgroundColor: Colors.red),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Login flow
|
// Login flow
|
||||||
@ -255,15 +296,15 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
||||||
/// Layout
|
/// Layout
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
double formWidth = widget.isTablet ? 400 : 300;
|
double formWidth = widget.isTablet ? 400 : 300;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
// color: Color(0xFF114D8B),
|
// color: Color(0xFF114D8B),
|
||||||
color: Color(0xFFf5f5f5),
|
color: Colors.white,
|
||||||
|
|
||||||
|
// color: Color(0xFFf5f5f5),
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@ -285,8 +326,9 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
// color: Colors.white,
|
// color: Colors.white,
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topRight: Radius.circular(250), // Rounded top-left corner
|
topRight: Radius.circular(250), // Rounded top-left corner
|
||||||
bottomRight:
|
bottomRight: Radius.circular(
|
||||||
Radius.circular(250), // Rounded bottom-left corner
|
250,
|
||||||
|
), // Rounded bottom-left corner
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// child: Padding(
|
// child: Padding(
|
||||||
@ -305,11 +347,15 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Image.asset(
|
// Image.asset(
|
||||||
'assets/images/login/logoNew.jpg',
|
// 'assets/images/login/logoNew.jpg',
|
||||||
|
// width: 200, // Optional: control size
|
||||||
|
// height: 100,
|
||||||
|
// fit: BoxFit.contain,
|
||||||
|
// ),
|
||||||
|
Container(
|
||||||
width: 200, // Optional: control size
|
width: 200, // Optional: control size
|
||||||
height: 100,
|
height: 100,
|
||||||
fit: BoxFit.contain,
|
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -320,9 +366,10 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
// width: 200, // Optional: control size
|
// width: 200, // Optional: control size
|
||||||
// height: 100,
|
// height: 100,
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
)),
|
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -332,20 +379,18 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
child: Container(
|
child: Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
// color: Colors.white,
|
// color: Colors.white,
|
||||||
|
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(25), // Rounded top-left corner
|
topLeft: Radius.circular(25), // Rounded top-left corner
|
||||||
bottomLeft: Radius.circular(25), // Rounded bottom-left corner
|
bottomLeft: Radius.circular(25), // Rounded bottom-left corner
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Center(
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(40),
|
padding: const EdgeInsets.all(10),
|
||||||
child: _buildForm(width: formWidth), // Fixed form width
|
child: _buildForm(width: formWidth), // Fixed form width
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -353,29 +398,57 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
|
|
||||||
/// **Reusable Login Form**
|
/// **Reusable Login Form**
|
||||||
Widget _buildForm({required double width}) {
|
Widget _buildForm({required double width}) {
|
||||||
return SizedBox(
|
return Column(
|
||||||
|
children: [
|
||||||
|
// width: width,
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Image.asset(
|
||||||
|
'assets/images/login/logoNew.jpg',
|
||||||
|
width: 180, // Optional: control size
|
||||||
|
height: 70,
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
width: width,
|
width: width,
|
||||||
child: Form(
|
child: Form(
|
||||||
key: _formKey,
|
key: _formKey,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
const SizedBox(height: 2),
|
||||||
Text(
|
Text(
|
||||||
"Sign In",
|
"Sign In",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 18,
|
fontSize: widget.isDesktop ? 20 : 18,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w700,
|
||||||
color: Color(0xFF212121)),
|
color: Colors.green,
|
||||||
|
// color: Color(0xFF212121),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
),
|
||||||
|
const SizedBox(height: 5),
|
||||||
Text(
|
Text(
|
||||||
"Welcome To TripApprovalTool",
|
"Welcome To TripApprovalTool",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Color(0xFF212121)),
|
|
||||||
|
color: Color(0xFF212121),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 18),
|
),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
/// **Email Field**
|
/// **Email Field**
|
||||||
if (!_isForgotPassword && !_showOtpResetFields) ...[
|
if (!_isForgotPassword && !_showOtpResetFields) ...[
|
||||||
@ -383,47 +456,61 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
decoration:
|
fontSize: 11,
|
||||||
_inputDecoration("Enter your email address").copyWith(
|
),
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your email address",
|
||||||
|
).copyWith(
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.email_outlined,
|
Icons.email_outlined,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) =>
|
validator:
|
||||||
value == null || value.isEmpty ? 'Required Email' : null,
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
|
? 'Required Email'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
/// **Password Field**
|
/// **Password Field**
|
||||||
_buildLabel("Password"),
|
_buildLabel("Password"),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
obscureText: _obscureText,
|
fontSize: 11,
|
||||||
decoration: _inputDecoration("Enter your password").copyWith(
|
|
||||||
prefixIcon: Icon(
|
|
||||||
Icons.key,
|
|
||||||
size: 16,
|
|
||||||
),
|
),
|
||||||
|
obscureText: _obscureText,
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your password",
|
||||||
|
).copyWith(
|
||||||
|
prefixIcon: Icon(Icons.key, size: 16),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscureText ? Icons.visibility_off : Icons.visibility,
|
_obscureText
|
||||||
|
? Icons.visibility_off
|
||||||
|
: Icons.visibility,
|
||||||
color: Color(0xFF12B24B),
|
color: Color(0xFF12B24B),
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed:
|
||||||
setState(() => _obscureText = !_obscureText),
|
() => setState(
|
||||||
|
() => _obscureText = !_obscureText,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) =>
|
),
|
||||||
value == null || value.isEmpty ? 'Required Password' : null,
|
validator:
|
||||||
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
|
? 'Required Password'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 10),
|
||||||
|
|
||||||
/// **Login Button**
|
/// **Login Button**
|
||||||
Row(
|
Row(
|
||||||
@ -432,31 +519,39 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => _login(context),
|
onPressed: () => _login(context),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(0xFF12B24B), // Button color
|
backgroundColor: Color(
|
||||||
foregroundColor: Colors.white, // Text color
|
0xFF12B24B,
|
||||||
|
), // Button color
|
||||||
|
foregroundColor:
|
||||||
|
Colors.white, // Text color
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 12),
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(18)),
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 10),
|
horizontal: 24,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Sign In",
|
"Sign In",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w800, fontSize: 15),
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 13.5,
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 3,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 3),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_sharp,
|
Icons.arrow_forward_sharp,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -464,54 +559,69 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
] else if (_isForgotPassword && !_showOtpResetFields) ...[
|
] else if (_isForgotPassword &&
|
||||||
|
!_showOtpResetFields) ...[
|
||||||
_buildLabel("Email Address"),
|
_buildLabel("Email Address"),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
decoration:
|
fontSize: 11,
|
||||||
_inputDecoration("Enter your email address").copyWith(
|
),
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your email address",
|
||||||
|
).copyWith(
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.email_outlined,
|
Icons.email_outlined,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) =>
|
validator:
|
||||||
value == null || value.isEmpty ? 'Required Email' : null,
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
|
? 'Required Email'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 10),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () => _onSubmit(context),
|
onPressed: () => _onSubmit(context),
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(0xFF12B24B), // Button color
|
backgroundColor: Color(
|
||||||
foregroundColor: Colors.white, // Text color
|
0xFF12B24B,
|
||||||
|
), // Button color
|
||||||
|
foregroundColor:
|
||||||
|
Colors.white, // Text color
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 12),
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(18)),
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 10),
|
horizontal: 24,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Submit",
|
"Submit",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w800, fontSize: 15),
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 13.5,
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 3,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 3),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_sharp,
|
Icons.arrow_forward_sharp,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -525,80 +635,103 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
controller: _emailController,
|
controller: _emailController,
|
||||||
readOnly: true,
|
readOnly: true,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
decoration:
|
fontSize: 11,
|
||||||
_inputDecoration("Enter your email address").copyWith(
|
),
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your email address",
|
||||||
|
).copyWith(
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.email_outlined,
|
Icons.email_outlined,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) =>
|
validator:
|
||||||
value == null || value.isEmpty ? 'Required Email' : null,
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
|
? 'Required Email'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 10),
|
||||||
_buildLabel("OTP"),
|
_buildLabel("OTP"),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _otpController,
|
controller: _otpController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
decoration: _inputDecoration("Enter your OTP").copyWith(
|
fontSize: 11,
|
||||||
|
),
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your OTP",
|
||||||
|
).copyWith(
|
||||||
prefixIcon: Icon(
|
prefixIcon: Icon(
|
||||||
Icons.email_outlined,
|
Icons.email_outlined,
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) =>
|
validator:
|
||||||
value == null || value.isEmpty ? 'Required OTP' : null,
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
|
? 'Required OTP'
|
||||||
|
: null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 10),
|
||||||
_buildLabel("New Password"),
|
_buildLabel("New Password"),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _newPasswordController,
|
controller: _newPasswordController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
obscureText: _obscureText,
|
fontSize: 11,
|
||||||
decoration:
|
|
||||||
_inputDecoration("Enter your new password").copyWith(
|
|
||||||
prefixIcon: Icon(
|
|
||||||
Icons.key,
|
|
||||||
size: 16,
|
|
||||||
),
|
),
|
||||||
|
obscureText: _obscureText,
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your new password",
|
||||||
|
).copyWith(
|
||||||
|
prefixIcon: Icon(Icons.key, size: 16),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscureText ? Icons.visibility_off : Icons.visibility,
|
_obscureText
|
||||||
|
? Icons.visibility_off
|
||||||
|
: Icons.visibility,
|
||||||
color: Color(0xFF12B24B),
|
color: Color(0xFF12B24B),
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed:
|
||||||
setState(() => _obscureText = !_obscureText),
|
() => setState(
|
||||||
|
() => _obscureText = !_obscureText,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) => value == null || value.isEmpty
|
),
|
||||||
|
validator:
|
||||||
|
(value) =>
|
||||||
|
value == null || value.isEmpty
|
||||||
? 'Required New Password'
|
? 'Required New Password'
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 10),
|
||||||
_buildLabel("Confirm Password"),
|
_buildLabel("Confirm Password"),
|
||||||
TextFormField(
|
TextFormField(
|
||||||
controller: _confirmPasswordController,
|
controller: _confirmPasswordController,
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w600, fontSize: 11),
|
fontWeight: FontWeight.w600,
|
||||||
obscureText: _obscureText,
|
fontSize: 11,
|
||||||
decoration:
|
|
||||||
_inputDecoration("Enter your confirm password").copyWith(
|
|
||||||
prefixIcon: Icon(
|
|
||||||
Icons.key,
|
|
||||||
size: 16,
|
|
||||||
),
|
),
|
||||||
|
obscureText: _obscureText,
|
||||||
|
decoration: _inputDecoration(
|
||||||
|
"Enter your confirm password",
|
||||||
|
).copyWith(
|
||||||
|
prefixIcon: Icon(Icons.key, size: 16),
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscureText ? Icons.visibility_off : Icons.visibility,
|
_obscureText
|
||||||
|
? Icons.visibility_off
|
||||||
|
: Icons.visibility,
|
||||||
color: Color(0xFF12B24B),
|
color: Color(0xFF12B24B),
|
||||||
size: 16,
|
size: 16,
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed:
|
||||||
setState(() => _obscureText = !_obscureText),
|
() => setState(
|
||||||
|
() => _obscureText = !_obscureText,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
validator: (value) {
|
validator: (value) {
|
||||||
@ -611,13 +744,14 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 10),
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (!_formKey.currentState!.validate()) return;
|
if (!_formKey.currentState!.validate())
|
||||||
|
return;
|
||||||
setState(() {
|
setState(() {
|
||||||
_isForgotPassword = false;
|
_isForgotPassword = false;
|
||||||
_showOtpResetFields = true;
|
_showOtpResetFields = true;
|
||||||
@ -626,31 +760,39 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
_onSubmit(context);
|
_onSubmit(context);
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(0xFF12B24B), // Button color
|
backgroundColor: Color(
|
||||||
foregroundColor: Colors.white, // Text color
|
0xFF12B24B,
|
||||||
|
), // Button color
|
||||||
|
foregroundColor:
|
||||||
|
Colors.white, // Text color
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 12),
|
horizontal: 24,
|
||||||
|
vertical: 12,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(18)),
|
borderRadius: BorderRadius.circular(18),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 10),
|
horizontal: 24,
|
||||||
|
vertical: 10,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Submit",
|
"Submit",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w800, fontSize: 15),
|
fontWeight: FontWeight.w800,
|
||||||
|
fontSize: 13.5,
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 3,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 3),
|
||||||
Icon(
|
Icon(
|
||||||
Icons.arrow_forward_sharp,
|
Icons.arrow_forward_sharp,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -659,7 +801,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 10),
|
||||||
if (!_isForgotPassword && !_showOtpResetFields)
|
if (!_isForgotPassword && !_showOtpResetFields)
|
||||||
Center(
|
Center(
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
@ -678,7 +820,8 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
|
|
||||||
color: Color(0xFF212121), // Text color
|
color: Color(0xFF212121), // Text color
|
||||||
decoration:
|
decoration:
|
||||||
TextDecoration.underline, // Underline the text
|
TextDecoration
|
||||||
|
.underline, // Underline the text
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -701,13 +844,14 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
|
|
||||||
color: Color(0xFF212121), // Text color
|
color: Color(0xFF212121), // Text color
|
||||||
decoration:
|
decoration:
|
||||||
TextDecoration.underline, // Underline the text
|
TextDecoration
|
||||||
|
.underline, // Underline the text
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 10),
|
||||||
if (!_isForgotPassword && !_showOtpResetFields)
|
if (!_isForgotPassword && !_showOtpResetFields)
|
||||||
Row(
|
Row(
|
||||||
children: [
|
children: [
|
||||||
@ -717,10 +861,14 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
handleMS();
|
handleMS();
|
||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.white, // Button color
|
backgroundColor:
|
||||||
foregroundColor: Colors.black, // Text color
|
Colors.white, // Button color
|
||||||
|
foregroundColor:
|
||||||
|
Colors.black, // Text color
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 5),
|
horizontal: 24,
|
||||||
|
vertical: 5,
|
||||||
|
),
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(18),
|
borderRadius: BorderRadius.circular(18),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
@ -731,18 +879,20 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
horizontal: 24, vertical: 5),
|
horizontal: 24,
|
||||||
|
vertical: 3,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Sign In With Microsoft",
|
"Sign In With Microsoft",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontWeight: FontWeight.w500, fontSize: 14),
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 13,
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
width: 3,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 3),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
'assets/images/login/microsoft.png',
|
'assets/images/login/microsoft.png',
|
||||||
width: 30, // Optional: control size
|
width: 30, // Optional: control size
|
||||||
@ -783,6 +933,13 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +954,8 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -826,8 +984,10 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
final url = '$apiUrl/auth/mslogin';
|
final url = '$apiUrl/auth/mslogin';
|
||||||
print(url);
|
print(url);
|
||||||
try {
|
try {
|
||||||
final response = await http
|
final response = await http.get(
|
||||||
.get(Uri.parse(url), headers: {'Content-Type': 'application/json'});
|
Uri.parse(url),
|
||||||
|
headers: {'Content-Type': 'application/json'},
|
||||||
|
);
|
||||||
print("inside try method");
|
print("inside try method");
|
||||||
if (response.statusCode == 200) {
|
if (response.statusCode == 200) {
|
||||||
final authUrl = json.decode(response.body)['auth_url'];
|
final authUrl = json.decode(response.body)['auth_url'];
|
||||||
|
|||||||
@ -24,14 +24,15 @@ class ForexScreen extends StatefulWidget {
|
|||||||
final Function(Map<String, dynamic>) onSaveForex;
|
final Function(Map<String, dynamic>) onSaveForex;
|
||||||
final String? loginUser;
|
final String? loginUser;
|
||||||
|
|
||||||
ForexScreen(
|
ForexScreen({
|
||||||
{required this.onClose,
|
required this.onClose,
|
||||||
this.apiData,
|
this.apiData,
|
||||||
required this.selectedItem,
|
required this.selectedItem,
|
||||||
required this.apiCountryData,
|
required this.apiCountryData,
|
||||||
required this.onSaveForex,
|
required this.onSaveForex,
|
||||||
required this.loginUser,
|
required this.loginUser,
|
||||||
required this.flightData});
|
required this.flightData,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_ForexScreenState createState() => _ForexScreenState();
|
_ForexScreenState createState() => _ForexScreenState();
|
||||||
@ -75,16 +76,18 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
"_cash",
|
"_cash",
|
||||||
"_checkForex",
|
"_checkForex",
|
||||||
"_deliveryLocation",
|
"_deliveryLocation",
|
||||||
"_comments"
|
"_comments",
|
||||||
];
|
];
|
||||||
|
|
||||||
String _formatDate(String? date) {
|
String _formatDate(String? date) {
|
||||||
if (date == null || date.isEmpty) return "";
|
if (date == null || date.isEmpty) return "";
|
||||||
try {
|
try {
|
||||||
DateTime parsedDate =
|
DateTime parsedDate = DateTime.parse(
|
||||||
DateTime.parse(date); // Assuming input is YYYY-MM-DD
|
date,
|
||||||
return DateFormat("dd-MM-yyyy")
|
); // Assuming input is YYYY-MM-DD
|
||||||
.format(parsedDate); // Convert to DD-MM-YYYY
|
return DateFormat(
|
||||||
|
"dd-MM-yyyy",
|
||||||
|
).format(parsedDate); // Convert to DD-MM-YYYY
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error formatting date: $e");
|
print("Error formatting date: $e");
|
||||||
return date; // Return as is if parsing fails
|
return date; // Return as is if parsing fails
|
||||||
@ -146,7 +149,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
"country_code": selectedCountry,
|
"country_code": selectedCountry,
|
||||||
"start_date": _formatDate(textControllers["_forexStartDate"]?.text),
|
"start_date": _formatDate(textControllers["_forexStartDate"]?.text),
|
||||||
"end_date": _formatDate(textControllers["_forexEndDate"]?.text),
|
"end_date": _formatDate(textControllers["_forexEndDate"]?.text),
|
||||||
"user_id": tripuserId
|
"user_id": tripuserId,
|
||||||
// "currency": selectedCurrency ?? "",
|
// "currency": selectedCurrency ?? "",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -195,10 +198,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
selectedDuration = responseData["duration"]?.toString() ?? "";
|
selectedDuration = responseData["duration"]?.toString() ?? "";
|
||||||
selectedQuotedAmount =
|
selectedQuotedAmount =
|
||||||
responseData["perdiem_amount"]?.toString() ?? "";
|
responseData["perdiem_amount"]?.toString() ?? "";
|
||||||
selectedCardPercent =
|
selectedCardPercent = int.tryParse(
|
||||||
int.tryParse(responseData["card_percentage"]?.toString() ?? "");
|
responseData["card_percentage"]?.toString() ?? "",
|
||||||
selectedCashPercent =
|
);
|
||||||
int.tryParse(responseData["cash_percentage"]?.toString() ?? "");
|
selectedCashPercent = int.tryParse(
|
||||||
|
responseData["cash_percentage"]?.toString() ?? "",
|
||||||
|
);
|
||||||
|
|
||||||
textControllers["_cardNumber"]?.text =
|
textControllers["_cardNumber"]?.text =
|
||||||
responseData["forex_card_no"]?.toString() ?? "";
|
responseData["forex_card_no"]?.toString() ?? "";
|
||||||
@ -249,17 +254,16 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Map<String, String?> getFlightTripDateRange(
|
Map<String, String?> getFlightTripDateRange(
|
||||||
List<Map<String, dynamic>> flightData) {
|
List<Map<String, dynamic>> flightData,
|
||||||
final allTrips = flightData
|
) {
|
||||||
|
final allTrips =
|
||||||
|
flightData
|
||||||
.expand((flight) => flight['trips'] ?? [])
|
.expand((flight) => flight['trips'] ?? [])
|
||||||
.whereType<Map<String, dynamic>>()
|
.whereType<Map<String, dynamic>>()
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (allTrips.isEmpty) {
|
if (allTrips.isEmpty) {
|
||||||
return {
|
return {'firstTripDate': null, 'lastTripDate': null};
|
||||||
'firstTripDate': null,
|
|
||||||
'lastTripDate': null,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
allTrips.sort((a, b) {
|
allTrips.sort((a, b) {
|
||||||
@ -352,18 +356,22 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// ✅ Only set controller after value is updated
|
// ✅ Only set controller after value is updated
|
||||||
// final parsedDate =
|
// final parsedDate =
|
||||||
// DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
|
// DateTime.tryParse(flightFirstTripDateNotifier.value ?? '');
|
||||||
final parsedDate = DateFormat("dd-MM-yyyy")
|
final parsedDate = DateFormat(
|
||||||
.parse(flightFirstTripDateNotifier.value ?? '');
|
"dd-MM-yyyy",
|
||||||
|
).parse(flightFirstTripDateNotifier.value ?? '');
|
||||||
if (parsedDate != null) {
|
if (parsedDate != null) {
|
||||||
textControllers["_forexStartDate"]?.text =
|
textControllers["_forexStartDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(parsedDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(parsedDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
final parsedEndDate = DateFormat("dd-MM-yyyy")
|
final parsedEndDate = DateFormat(
|
||||||
.parse(flightLastTripDateNotifier.value ?? '');
|
"dd-MM-yyyy",
|
||||||
|
).parse(flightLastTripDateNotifier.value ?? '');
|
||||||
if (parsedEndDate != null) {
|
if (parsedEndDate != null) {
|
||||||
textControllers["_forexEndDate"]?.text =
|
textControllers["_forexEndDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(parsedEndDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(parsedEndDate);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -392,8 +400,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
textControllers["_cardNumber"] = initController("card_number");
|
textControllers["_cardNumber"] = initController("card_number");
|
||||||
textControllers["_card"] = initController("deposit_on_card");
|
textControllers["_card"] = initController("deposit_on_card");
|
||||||
textControllers["_cash"] = initController("deposit_on_cash");
|
textControllers["_cash"] = initController("deposit_on_cash");
|
||||||
textControllers["_deliveryLocation"] =
|
textControllers["_deliveryLocation"] = initController(
|
||||||
initController("delivery_location");
|
"delivery_location",
|
||||||
|
);
|
||||||
textControllers["_comments"] = initController("comments");
|
textControllers["_comments"] = initController("comments");
|
||||||
|
|
||||||
// Set dropdown values
|
// Set dropdown values
|
||||||
@ -401,9 +410,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
selectedCurrency = widget.selectedItem!["currency"] as String?;
|
selectedCurrency = widget.selectedItem!["currency"] as String?;
|
||||||
selectedDuration = widget.selectedItem!["duration"] as String?;
|
selectedDuration = widget.selectedItem!["duration"] as String?;
|
||||||
selectedCardPercent = int.tryParse(
|
selectedCardPercent = int.tryParse(
|
||||||
widget.selectedItem!["card_percentage"]?.toString() ?? "");
|
widget.selectedItem!["card_percentage"]?.toString() ?? "",
|
||||||
|
);
|
||||||
selectedCashPercent = int.tryParse(
|
selectedCashPercent = int.tryParse(
|
||||||
widget.selectedItem!["cash_percentage"]?.toString() ?? "");
|
widget.selectedItem!["cash_percentage"]?.toString() ?? "",
|
||||||
|
);
|
||||||
selectedPerdiemAmount = widget.selectedItem!["perdiem_amount"] as String?;
|
selectedPerdiemAmount = widget.selectedItem!["perdiem_amount"] as String?;
|
||||||
isChecked =
|
isChecked =
|
||||||
widget.selectedItem!["have_card"] == "1"; // Convert string to bool
|
widget.selectedItem!["have_card"] == "1"; // Convert string to bool
|
||||||
@ -473,7 +484,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
|
|
||||||
if (startDateString == null || endDateString == null) return;
|
if (startDateString == null || endDateString == null) return;
|
||||||
print(
|
print(
|
||||||
"Calculate 3 - StarrtDAte: $startDateString --EndDate: $endDateString");
|
"Calculate 3 - StarrtDAte: $startDateString --EndDate: $endDateString",
|
||||||
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Parse the dates from string
|
// Parse the dates from string
|
||||||
@ -548,7 +560,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (quotedAmount != null) {
|
if (quotedAmount != null) {
|
||||||
// fifteenPercent = (quotedAmount * 15) ~/ 100;
|
// fifteenPercent = (quotedAmount * 15) ~/ 100;
|
||||||
print("selectedCardPercent - $selectedCashPercent");
|
print("selectedCardPercent - $selectedCashPercent");
|
||||||
fifteenPercent = (quotedAmount * selectedCashPercent!) ~/
|
fifteenPercent =
|
||||||
|
(quotedAmount * selectedCashPercent!) ~/
|
||||||
100; // Calculate 15% (integer division)
|
100; // Calculate 15% (integer division)
|
||||||
remainingAmount = quotedAmount - fifteenPercent; // Subtract from total
|
remainingAmount = quotedAmount - fifteenPercent; // Subtract from total
|
||||||
|
|
||||||
@ -587,10 +600,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
int checkValidAmount = cashAmount + enteredAmount;
|
int checkValidAmount = cashAmount + enteredAmount;
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"checkValidAmount - $checkValidAmount - $enteredAmount - $cashAmount");
|
"checkValidAmount - $checkValidAmount - $enteredAmount - $cashAmount",
|
||||||
|
);
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"CAsh - $cashAmount- CaRd- $enteredAmount - $calculateAmnt - selectedQuotedAmount - $qouteAmount");
|
"CAsh - $cashAmount- CaRd- $enteredAmount - $calculateAmnt - selectedQuotedAmount - $qouteAmount",
|
||||||
|
);
|
||||||
|
|
||||||
if (enteredAmount == null || calculateAmnt > qouteAmount!) {
|
if (enteredAmount == null || calculateAmnt > qouteAmount!) {
|
||||||
errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount";
|
errorMessages["deposit_on_card"] = "Amount cannot exceed $qouteAmount";
|
||||||
@ -619,19 +634,20 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
int checkValidAmount = cardAmount! + enteredAmount;
|
int checkValidAmount = cardAmount! + enteredAmount;
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"checkValidAmountCash - $checkValidAmount -cash- $enteredAmount -Card - $cardAmount - quotedAmount- $quotedAmount");
|
"checkValidAmountCash - $checkValidAmount -cash- $enteredAmount -Card - $cardAmount - quotedAmount- $quotedAmount",
|
||||||
|
);
|
||||||
|
|
||||||
print("Difference - $difference");
|
print("Difference - $difference");
|
||||||
print('CardAmount - $cardAmount');
|
print('CardAmount - $cardAmount');
|
||||||
textControllers["_card"]?.text = difference.toString();
|
textControllers["_card"]?.text = difference.toString();
|
||||||
|
|
||||||
// if (enteredAmount > fifteenPercent) {
|
if (enteredAmount > fifteenPercent) {
|
||||||
// errorMessages["deposit_on_cash"] = "Amount cannot exceed $fifteenPercent";
|
errorMessages["deposit_on_cash"] = "Amount cannot exceed $fifteenPercent";
|
||||||
// } else if (checkValidAmount == quotedAmount) {
|
} else if (checkValidAmount == quotedAmount) {
|
||||||
// errorMessages["deposit_on_card"] = " "; // Clear error if valid
|
errorMessages["deposit_on_card"] = " "; // Clear error if valid
|
||||||
// } else {
|
} else {
|
||||||
// errorMessages["deposit_on_cash"] = ""; // Clear error if valid
|
errorMessages["deposit_on_cash"] = ""; // Clear error if valid
|
||||||
// }
|
}
|
||||||
|
|
||||||
// Refresh UI if using StatefulWidget
|
// Refresh UI if using StatefulWidget
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@ -653,10 +669,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
void _validateDates() {
|
void _validateDates() {
|
||||||
print("VALiDATING DATES");
|
print("VALiDATING DATES");
|
||||||
|
|
||||||
DateTime? startDate =
|
DateTime? startDate = _parseDate(
|
||||||
_parseDate(textControllers["_forexStartDate"]?.text ?? "");
|
textControllers["_forexStartDate"]?.text ?? "",
|
||||||
DateTime? endDate =
|
);
|
||||||
_parseDate(textControllers["_forexEndDate"]?.text ?? "");
|
DateTime? endDate = _parseDate(
|
||||||
|
textControllers["_forexEndDate"]?.text ?? "",
|
||||||
|
);
|
||||||
|
|
||||||
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
if (startDate != null && endDate != null && endDate.isBefore(startDate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -672,9 +690,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(
|
||||||
|
builder: (context, sizingInfo) {
|
||||||
bool isMobile = sizingInfo.isMobile;
|
bool isMobile = sizingInfo.isMobile;
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
// color: Color(0xFFF4F4FB),
|
// color: Color(0xFFF4F4FB),
|
||||||
@ -689,13 +709,14 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
child: Center(
|
child: Center(
|
||||||
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
child: Column(children: _buildAccomadtionForm(isDesktop)),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
List<Widget> _buildAccomadtionForm(bool isDesktop) {
|
||||||
@ -714,9 +735,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
...buildResponsiveRow(_buildFirstRow(isDesktop)),
|
||||||
SizedBox(
|
SizedBox(height: 5),
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
// Align(
|
// Align(
|
||||||
// alignment: Alignment.centerLeft,
|
// alignment: Alignment.centerLeft,
|
||||||
// child: Text(
|
// child: Text(
|
||||||
@ -743,9 +762,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// Divider(
|
// Divider(
|
||||||
// thickness: 0.3,
|
// thickness: 0.3,
|
||||||
// ),
|
// ),
|
||||||
SizedBox(
|
SizedBox(height: 10),
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
...buildResponsiveRow(_buildSecondRow(isDesktop)),
|
...buildResponsiveRow(_buildSecondRow(isDesktop)),
|
||||||
...buildResponsiveRow(_buildCardDetailsRow(isDesktop)),
|
...buildResponsiveRow(_buildCardDetailsRow(isDesktop)),
|
||||||
...buildResponsiveRow(_buildForexCard(isDesktop)),
|
...buildResponsiveRow(_buildForexCard(isDesktop)),
|
||||||
@ -769,8 +786,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
initialDate = DateTime.parse(flightFirstTripDateNotifier.value!);
|
initialDate = DateTime.parse(flightFirstTripDateNotifier.value!);
|
||||||
// textControllers["_forexStartDate"]?.text =
|
// textControllers["_forexStartDate"]?.text =
|
||||||
// DateFormat('yyyy-MM-dd').format(initialDate);
|
// DateFormat('yyyy-MM-dd').format(initialDate);
|
||||||
textControllers["_forexStartDate"]?.text =
|
textControllers["_forexStartDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(initialDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(initialDate);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
initialDate = today;
|
initialDate = today;
|
||||||
}
|
}
|
||||||
@ -804,8 +822,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
textControllers["_forexStartDate"]?.text =
|
textControllers["_forexStartDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -854,8 +873,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedEndDate = pickedDate;
|
_selectedEndDate = pickedDate;
|
||||||
textControllers["_forexEndDate"]?.text =
|
textControllers["_forexEndDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(pickedDate);
|
||||||
// textControllers["_forexEndDate"]?.text =
|
// textControllers["_forexEndDate"]?.text =
|
||||||
// DateFormat('dd-MM-yyyy').format(initialDate);
|
// DateFormat('dd-MM-yyyy').format(initialDate);
|
||||||
});
|
});
|
||||||
@ -871,7 +891,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -888,10 +909,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
await _selectCheckOutDate(context);
|
await _selectCheckOutDate(context);
|
||||||
|
|
||||||
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
||||||
DateTime? startDate =
|
DateTime? startDate = _parseDate(
|
||||||
_parseDate(textControllers["_forexStartDate"]!.text);
|
textControllers["_forexStartDate"]!.text,
|
||||||
DateTime? endDate =
|
);
|
||||||
_parseDate(textControllers["_forexEndDate"]!.text);
|
DateTime? endDate = _parseDate(
|
||||||
|
textControllers["_forexEndDate"]!.text,
|
||||||
|
);
|
||||||
|
|
||||||
if (startDate != null &&
|
if (startDate != null &&
|
||||||
endDate != null &&
|
endDate != null &&
|
||||||
@ -914,13 +937,18 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Select Date",
|
labelText: "Select Date",
|
||||||
labelStyle:
|
labelStyle: const TextStyle(
|
||||||
const TextStyle(fontSize: 12, color: Colors.grey),
|
fontSize: 12,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon: const Icon(Icons.calendar_today,
|
suffixIcon: const Icon(
|
||||||
size: 16, color: Colors.grey),
|
Icons.calendar_today,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -936,12 +964,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -950,7 +973,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -964,10 +988,12 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
await _selectForexEndDate(context);
|
await _selectForexEndDate(context);
|
||||||
|
|
||||||
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
if (textControllers["_forexEndDate"]!.text.isNotEmpty) {
|
||||||
DateTime? startDate =
|
DateTime? startDate = _parseDate(
|
||||||
_parseDate(textControllers["_forexStartDate"]!.text);
|
textControllers["_forexStartDate"]!.text,
|
||||||
DateTime? endDate =
|
);
|
||||||
_parseDate(textControllers["_forexEndDate"]!.text);
|
DateTime? endDate = _parseDate(
|
||||||
|
textControllers["_forexEndDate"]!.text,
|
||||||
|
);
|
||||||
|
|
||||||
if (startDate != null &&
|
if (startDate != null &&
|
||||||
endDate != null &&
|
endDate != null &&
|
||||||
@ -995,8 +1021,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon: Icon(Icons.calendar_today,
|
suffixIcon: Icon(
|
||||||
size: 16, color: Colors.grey),
|
Icons.calendar_today,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1013,12 +1042,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1027,7 +1051,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1045,7 +1070,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -1071,7 +1097,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// Map country codes to country names
|
// Map country codes to country names
|
||||||
countryMap = {
|
countryMap = {
|
||||||
for (var item in countryList)
|
for (var item in countryList)
|
||||||
item['country_code'] as String: item['country_name'] as String
|
item['country_code'] as String: item['country_name'] as String,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Extract only country codes for processing
|
// Extract only country codes for processing
|
||||||
@ -1101,7 +1127,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1124,12 +1151,11 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
dropdownSearchDecoration: InputDecoration(
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
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(
|
||||||
@ -1140,7 +1166,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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 = countryMap.entries
|
selectedCountry =
|
||||||
|
countryMap.entries
|
||||||
.firstWhere((entry) => entry.value == newValue)
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
.key;
|
.key;
|
||||||
_onCountryChanged(selectedCountry);
|
_onCountryChanged(selectedCountry);
|
||||||
@ -1164,13 +1191,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// height: 8,
|
// height: 8,
|
||||||
// ),
|
// ),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
SizedBox(
|
SizedBox(width: MediaQuery.of(context).size.width * 0.048)
|
||||||
width: MediaQuery.of(context).size.width * 0.048,
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
SizedBox(
|
SizedBox(height: 8),
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -1179,7 +1202,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1202,7 +1226,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1211,12 +1236,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
// if (isDesktop)SizedBox(width: 8,) else SizedBox(height: 8,),
|
// if (isDesktop)SizedBox(width: 8,) else SizedBox(height: 8,),
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1225,7 +1245,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1243,7 +1264,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -1279,7 +1301,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
Container(
|
Container(
|
||||||
@ -1298,8 +1321,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
},
|
},
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(
|
FilteringTextInputFormatter.allow(
|
||||||
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
RegExp(r'^\d*\.?\d*$'),
|
||||||
|
), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1310,7 +1334,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
// CustomTextFieldItnerarySubWrapper(
|
// CustomTextFieldItnerarySubWrapper(
|
||||||
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
||||||
// isFocused: focusStates["_transport"] ?? false,
|
// isFocused: focusStates["_transport"] ?? false,
|
||||||
@ -1339,14 +1363,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) SizedBox(width: 10) else SizedBox(height: 8),
|
||||||
SizedBox(
|
|
||||||
width: 10,
|
|
||||||
)
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1355,7 +1372,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
Container(
|
Container(
|
||||||
@ -1374,8 +1392,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
},
|
},
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(
|
FilteringTextInputFormatter.allow(
|
||||||
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
RegExp(r'^\d*\.?\d*$'),
|
||||||
|
), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1386,7 +1405,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
),
|
||||||
// CustomTextFieldItnerarySubWrapper(
|
// CustomTextFieldItnerarySubWrapper(
|
||||||
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
||||||
// isFocused: focusStates["_accomodation"] ?? false,
|
// isFocused: focusStates["_accomodation"] ?? false,
|
||||||
@ -1415,14 +1434,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) SizedBox(width: 10) else SizedBox(height: 8),
|
||||||
SizedBox(
|
|
||||||
width: 10,
|
|
||||||
)
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1431,14 +1443,14 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 5),
|
SizedBox(height: 5),
|
||||||
Container(
|
Container(
|
||||||
color: Colors.yellow.shade50,
|
color: Colors.yellow.shade50,
|
||||||
padding: const EdgeInsets.only(left: 10),
|
padding: const EdgeInsets.only(left: 10),
|
||||||
width:
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.06 : null,
|
||||||
isDesktop ? MediaQuery.of(context).size.width * 0.06 : null,
|
|
||||||
height: 30,
|
height: 30,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
focusNode: focusNodes["_telephone"],
|
focusNode: focusNodes["_telephone"],
|
||||||
@ -1451,8 +1463,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
},
|
},
|
||||||
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
keyboardType: TextInputType.numberWithOptions(decimal: true),
|
||||||
inputFormatters: [
|
inputFormatters: [
|
||||||
FilteringTextInputFormatter.allow(RegExp(
|
FilteringTextInputFormatter.allow(
|
||||||
r'^\d*\.?\d*$')), // Allow only positive numbers with optional decimal
|
RegExp(r'^\d*\.?\d*$'),
|
||||||
|
), // Allow only positive numbers with optional decimal
|
||||||
],
|
],
|
||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
@ -1462,7 +1475,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
),
|
||||||
// CustomTextFieldItnerarySubWrapper(
|
// CustomTextFieldItnerarySubWrapper(
|
||||||
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
// width: isDesktop ? MediaQuery.of(context).size.width * 0.07 : null,
|
||||||
// isFocused: focusStates["_telephone"] ?? false,
|
// isFocused: focusStates["_telephone"] ?? false,
|
||||||
@ -1491,14 +1505,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop) SizedBox(width: 40) else SizedBox(height: 8),
|
||||||
SizedBox(
|
|
||||||
width: 40,
|
|
||||||
)
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -1507,7 +1514,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1525,7 +1533,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
// decoration: const InputDecoration(
|
// decoration: const InputDecoration(
|
||||||
// labelText: "To",
|
// labelText: "To",
|
||||||
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
// labelStyle: TextStyle(fontSize: 12, color: Colors.grey),
|
||||||
@ -1545,19 +1554,24 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
List<Widget> _buildCardDetailsRow(bool isDesktop) {
|
List<Widget> _buildCardDetailsRow(bool isDesktop) {
|
||||||
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
List<dynamic> purposeList = widget.apiData?['flight_class'] ?? [];
|
||||||
|
|
||||||
List<DropdownMenuItem<String>> dropdownItems = purposeList
|
List<DropdownMenuItem<String>> dropdownItems =
|
||||||
.map((item) => DropdownMenuItem<String>(
|
purposeList
|
||||||
|
.map(
|
||||||
|
(item) => DropdownMenuItem<String>(
|
||||||
value: item['dropdown_value'],
|
value: item['dropdown_value'],
|
||||||
child: Text(item['dropdown_value']),
|
child: Text(item['dropdown_value']),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
if (dropdownItems.isEmpty) {
|
if (dropdownItems.isEmpty) {
|
||||||
dropdownItems.add(
|
dropdownItems.add(
|
||||||
DropdownMenuItem<String>(
|
DropdownMenuItem<String>(
|
||||||
value: null,
|
value: null,
|
||||||
child: Text("No options available",
|
child: Text(
|
||||||
style: TextStyle(color: Colors.grey)),
|
"No options available",
|
||||||
|
style: TextStyle(color: Colors.grey),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1574,7 +1588,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1590,7 +1605,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
// errorMessages["deposit_on_cash"] = "";
|
// errorMessages["deposit_on_cash"] = "";
|
||||||
_validateCashAmount(
|
_validateCashAmount(
|
||||||
value); // Call validation when text changes
|
value,
|
||||||
|
); // Call validation when text changes
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Cash",
|
labelText: "Cash",
|
||||||
@ -1613,12 +1629,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1628,7 +1639,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1643,7 +1655,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
_validateCardAmount(
|
_validateCardAmount(
|
||||||
value); // Call validation when text changes
|
value,
|
||||||
|
); // Call validation when text changes
|
||||||
},
|
},
|
||||||
decoration: const InputDecoration(
|
decoration: const InputDecoration(
|
||||||
labelText: "Card",
|
labelText: "Card",
|
||||||
@ -1665,12 +1678,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
if (isDesktop)
|
if (isDesktop) Spacer() else SizedBox(height: 8),
|
||||||
Spacer()
|
|
||||||
else
|
|
||||||
SizedBox(
|
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -1680,7 +1688,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1698,7 +1707,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontSize: 13,
|
fontSize: 13,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1826,7 +1836,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
@ -1853,9 +1864,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop) Spacer(),
|
if (isDesktop) Spacer(),
|
||||||
SizedBox(
|
SizedBox(height: 5),
|
||||||
height: 5,
|
|
||||||
),
|
|
||||||
// Actions row remains a Row
|
// Actions row remains a Row
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
@ -1879,7 +1888,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldForexWrapper(
|
CustomTextFieldForexWrapper(
|
||||||
@ -1919,16 +1929,17 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
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),
|
||||||
CustomTextFieldWrapper(
|
CustomTextFieldWrapper(
|
||||||
isFocused: focusStates["_deliveryLocation"] ??
|
isFocused:
|
||||||
|
focusStates["_deliveryLocation"] ??
|
||||||
false, // Dropdown doesn't use focus
|
false, // Dropdown doesn't use focus
|
||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
width: isDesktop
|
width:
|
||||||
? MediaQuery.of(context).size.width * 0.45
|
isDesktop ? MediaQuery.of(context).size.width * 0.45 : null,
|
||||||
: null,
|
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 35,
|
height: 35,
|
||||||
child: TextField(
|
child: TextField(
|
||||||
@ -1955,13 +1966,9 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (isDesktop)
|
if (isDesktop)
|
||||||
SizedBox(
|
SizedBox(width: MediaQuery.of(context).size.width * 0.04)
|
||||||
width: MediaQuery.of(context).size.width * 0.04,
|
|
||||||
)
|
|
||||||
else
|
else
|
||||||
SizedBox(
|
SizedBox(height: 8),
|
||||||
height: 8,
|
|
||||||
),
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@ -1997,7 +2004,8 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF575A74)),
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -2015,9 +2023,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Colors.grey[400], // Light grey color
|
backgroundColor: Colors.grey[400], // Light grey color
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -2026,7 +2032,6 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 10), // Space between buttons
|
SizedBox(width: 10), // Space between buttons
|
||||||
|
|
||||||
// Save Changes Button
|
// Save Changes Button
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -2034,9 +2039,7 @@ class _ForexScreenState extends State<ForexScreen> {
|
|||||||
},
|
},
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
backgroundColor: Color(0xFF114D8B), // Primary color for save
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||||
borderRadius: BorderRadius.circular(8),
|
|
||||||
),
|
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@ -42,7 +42,7 @@ class _PlaceholdersModalState extends State<PlaceholdersModal> {
|
|||||||
content: Container(
|
content: Container(
|
||||||
width:
|
width:
|
||||||
isDesktop
|
isDesktop
|
||||||
? MediaQuery.of(context).size.width * 0.3
|
? MediaQuery.of(context).size.width * 0.4
|
||||||
: double.maxFinite,
|
: double.maxFinite,
|
||||||
// Set max height so ListView knows constraints
|
// Set max height so ListView knows constraints
|
||||||
height: 300,
|
height: 300,
|
||||||
|
|||||||
@ -642,7 +642,7 @@ class TemplateState extends State<Template> {
|
|||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
height: 200,
|
height: MediaQuery.of(context).size.height * 0.3,
|
||||||
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),
|
||||||
|
|||||||
830
lib/Screens/myTemplates/templateForex.dart
Normal file
830
lib/Screens/myTemplates/templateForex.dart
Normal file
@ -0,0 +1,830 @@
|
|||||||
|
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_quill/flutter_quill.dart' hide Text;
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_quill/flutter_quill.dart' hide Text;
|
||||||
|
import 'package:flutter_quill/quill_delta.dart';
|
||||||
|
import 'package:flutter_quill/quill_delta.dart' as quill;
|
||||||
|
import 'package:flutter_quill_delta_from_html/flutter_quill_delta_from_html.dart';
|
||||||
|
import 'package:flutter_quill_extensions/flutter_quill_extensions.dart';
|
||||||
|
import 'package:frontend/Screens/myTemplates/templateForex.dart'
|
||||||
|
as _editorFocusNode;
|
||||||
|
import 'package:frontend/Screens/myTemplates/templateForex.dart'
|
||||||
|
as _editorScrollController;
|
||||||
|
import 'package:frontend/Screens/myTemplates/templateForex.dart' as _controller;
|
||||||
|
import 'package:html2md/html2md.dart' as html2md;
|
||||||
|
import 'package:vsc_quill_delta_to_html/vsc_quill_delta_to_html.dart';
|
||||||
|
|
||||||
|
import 'package:flutter_quill/flutter_quill.dart' as quill;
|
||||||
|
import 'package:html/parser.dart' show parse;
|
||||||
|
import 'package:html/dom.dart' as dom hide Element, Text;
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_quill/flutter_quill.dart';
|
||||||
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||||
|
import 'package:flutter_quill/flutter_quill_internal.dart';
|
||||||
|
import 'package:flutter_quill/quill_delta.dart';
|
||||||
|
|
||||||
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:path/path.dart' as path;
|
||||||
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import '../../config/apiUrl.dart';
|
||||||
|
import '../../routes/custom_appBar.dart';
|
||||||
|
import '../../routes/custom_drawer.dart';
|
||||||
|
import '../../services/apiService.dart';
|
||||||
|
import '../../utils/auth_utils.dart';
|
||||||
|
import '../../widgets/custom_user_travel.dart';
|
||||||
|
import 'dialog_placeholders.dart';
|
||||||
|
|
||||||
|
class TemplateForex extends StatefulWidget {
|
||||||
|
final Map<String, dynamic>? templateData;
|
||||||
|
|
||||||
|
const TemplateForex({super.key, required this.templateData});
|
||||||
|
|
||||||
|
static TemplateForex fromState(GoRouterState state) {
|
||||||
|
return TemplateForex(templateData: state.extra as Map<String, dynamic>?);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
TemplateForexState createState() => TemplateForexState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TemplateForexState extends State<TemplateForex> {
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
|
// final QuillController _controller = QuillController.basic();
|
||||||
|
String? orgId;
|
||||||
|
String? userId;
|
||||||
|
Color layoutColor = Colors.redAccent;
|
||||||
|
Color bodyColor = Colors.white;
|
||||||
|
final Map<String, TextEditingController> controllers = {};
|
||||||
|
List<String> dataHeader = ["subject"];
|
||||||
|
List<String> placeholders = [];
|
||||||
|
|
||||||
|
late QuillController _controller = QuillController.basic();
|
||||||
|
final FocusNode _focusNode = FocusNode();
|
||||||
|
|
||||||
|
late int templateId = 0;
|
||||||
|
late String templateName = "";
|
||||||
|
late List<Map<String, dynamic>> placeholderList = [];
|
||||||
|
|
||||||
|
Map<String, dynamic> get TemplateData {
|
||||||
|
final data = {
|
||||||
|
"org_id": orgId,
|
||||||
|
|
||||||
|
// "template_id": templateId,
|
||||||
|
// "template_name": controllers["templateName"]?.text,
|
||||||
|
"template_id": templateId,
|
||||||
|
"template_name": templateName,
|
||||||
|
"subject": controllers["subject"]?.text,
|
||||||
|
"body_html": DeltaToHTML.encodeJson(
|
||||||
|
_controller.document.toDelta().toJson(),
|
||||||
|
),
|
||||||
|
// "body_html": jsonEncode(_controller.document.toDelta().toJson()),
|
||||||
|
|
||||||
|
// "body_html": _controller,
|
||||||
|
// "body_html": convertQuillDocToHtml(_controller.document),
|
||||||
|
// ✅ convert delta to HTML
|
||||||
|
"placeholder": jsonEncode(placeholderList),
|
||||||
|
// "created_by": userId
|
||||||
|
};
|
||||||
|
print('start 123');
|
||||||
|
print(jsonEncode(_controller.document.toDelta().toJson()));
|
||||||
|
// print(jsonEncode(_controller.document));
|
||||||
|
// Only add group_id if it's an edit operation
|
||||||
|
// if (widget.templateData != null && widget.templateData!.containsKey('group_id')) {
|
||||||
|
// data["template_id"] = templateData;
|
||||||
|
// }
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
|
for (var field in dataHeader) {
|
||||||
|
controllers[field] = TextEditingController();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateData();
|
||||||
|
loadinitializeData();
|
||||||
|
loadInitialData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
// void dispose() {
|
||||||
|
// // controllers.dispose();
|
||||||
|
// // _editorScrollController.dispose();
|
||||||
|
// _editorFocusNode.dispose();
|
||||||
|
// super.dispose();
|
||||||
|
// }
|
||||||
|
void loadinitializeData() async {
|
||||||
|
orgId = await getOrgId();
|
||||||
|
userId = await getUserId();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loadInitialData() async {
|
||||||
|
String? layoutString = await getLayoutColor();
|
||||||
|
String? bodyStringColor = await getBodyColor();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
layoutColor =
|
||||||
|
layoutString != null
|
||||||
|
? Color(int.parse(layoutString))
|
||||||
|
: Colors.redAccent;
|
||||||
|
|
||||||
|
bodyColor =
|
||||||
|
bodyStringColor != null
|
||||||
|
? Color(int.parse(bodyStringColor))
|
||||||
|
: Colors.white;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
String convertQuillDocToHtml(quill.Document doc) {
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
|
||||||
|
print("convertQuillDocToHtml");
|
||||||
|
for (final op in doc.toDelta().toList()) {
|
||||||
|
final insert = op.data;
|
||||||
|
final attrs = op.attributes ?? {};
|
||||||
|
|
||||||
|
if (insert is String) {
|
||||||
|
var content = insert;
|
||||||
|
|
||||||
|
// Handle formatting (bold, italic, etc.)
|
||||||
|
if (attrs.containsKey('bold')) {
|
||||||
|
content = '<strong>$content</strong>';
|
||||||
|
}
|
||||||
|
if (attrs.containsKey('italic')) {
|
||||||
|
content = '<em>$content</em>';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrap each paragraph with <p>
|
||||||
|
if (content.trim().isNotEmpty) {
|
||||||
|
buffer.write('<p>${content.trim()}</p>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String convertQuillDocToHtml2(quill.Document doc) {
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
final lines = <String>[];
|
||||||
|
final delta = doc.toDelta();
|
||||||
|
|
||||||
|
String applyStyles(String text, Map<String, dynamic>? attrs) {
|
||||||
|
if (attrs == null) return text;
|
||||||
|
if (attrs.containsKey('bold')) {
|
||||||
|
text = '<strong>$text</strong>';
|
||||||
|
}
|
||||||
|
if (attrs.containsKey('italic')) {
|
||||||
|
text = '<em>$text</em>';
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final op in delta.toList()) {
|
||||||
|
final insert = op.data;
|
||||||
|
final attrs = op.attributes;
|
||||||
|
|
||||||
|
if (insert is String) {
|
||||||
|
final parts = insert.split('\n');
|
||||||
|
for (int i = 0; i < parts.length; i++) {
|
||||||
|
final part = applyStyles(parts[i], attrs);
|
||||||
|
lines.add(part);
|
||||||
|
|
||||||
|
if (i < parts.length - 1) {
|
||||||
|
// End of line: wrap accumulated content into <p>
|
||||||
|
final joined = lines.join('');
|
||||||
|
if (joined.trim().isNotEmpty) {
|
||||||
|
buffer.writeln('<p>${joined.trim()}</p>');
|
||||||
|
}
|
||||||
|
lines.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add remaining lines
|
||||||
|
final joined = lines.join('');
|
||||||
|
if (joined.trim().isNotEmpty) {
|
||||||
|
buffer.writeln('<p>${joined.trim()}</p>');
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String extractPlainTextFromHtml(String html) {
|
||||||
|
final regex = RegExp(r'<p>(.*?)<\/p>', multiLine: true, dotAll: true);
|
||||||
|
final matches = regex.allMatches(html);
|
||||||
|
|
||||||
|
final buffer = StringBuffer();
|
||||||
|
for (final match in matches) {
|
||||||
|
final text = match.group(1)?.replaceAll(RegExp(r'<[^>]*>'), '') ?? '';
|
||||||
|
buffer.writeln(text.trim());
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
String decodeHtmlEntities(String text) {
|
||||||
|
return text
|
||||||
|
.replaceAll(' ', ' ')
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')
|
||||||
|
.replaceAll('"', '"')
|
||||||
|
.replaceAll(''', "'"); // add more as needed
|
||||||
|
}
|
||||||
|
|
||||||
|
// quill.Document convertSimpleHtmlToQuill(String htmlString) {
|
||||||
|
// final delta = quill.Delta();
|
||||||
|
// final doc = html_parser.parse(htmlString);
|
||||||
|
// final body = doc.body;
|
||||||
|
//
|
||||||
|
// void walk(Node node) {
|
||||||
|
// if (node is Text) {
|
||||||
|
// delta.insert(node.text);
|
||||||
|
// } else if (node is Element) {
|
||||||
|
// switch (node.localName) {
|
||||||
|
// case 'p':
|
||||||
|
// node.nodes.forEach(walk);
|
||||||
|
// delta.insert('\n');
|
||||||
|
// break;
|
||||||
|
// case 'br':
|
||||||
|
// delta.insert('\n');
|
||||||
|
// break;
|
||||||
|
// case 'strong':
|
||||||
|
// case 'b':
|
||||||
|
// delta.insert(node.text, {'bold': true});
|
||||||
|
// break;
|
||||||
|
// case 'em':
|
||||||
|
// case 'i':
|
||||||
|
// delta.insert(node.text, {'italic': true});
|
||||||
|
// break;
|
||||||
|
// case 'a':
|
||||||
|
// delta.insert(node.text, {'link': node.attributes['href']});
|
||||||
|
// break;
|
||||||
|
// default:
|
||||||
|
// node.nodes.forEach(walk);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (body != null) {
|
||||||
|
// walk(body);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return quill.Document.fromDelta(delta..insert('\n'));
|
||||||
|
// }
|
||||||
|
|
||||||
|
String formatTemplateName(String input) {
|
||||||
|
return input
|
||||||
|
.split('_') // split by underscore
|
||||||
|
.map(
|
||||||
|
(word) =>
|
||||||
|
word.isNotEmpty
|
||||||
|
? '${word[0].toUpperCase()}${word.substring(1)}'
|
||||||
|
: '',
|
||||||
|
)
|
||||||
|
.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateData() async {
|
||||||
|
// Ensure apiselectedUser is not null before printing
|
||||||
|
if (widget.templateData != null) {
|
||||||
|
print("API Selected User Has Data - ${widget.templateData}");
|
||||||
|
print(
|
||||||
|
"API Selected User Has - ${widget.templateData?["templateData"]?["subject"]}",
|
||||||
|
);
|
||||||
|
setState(() {
|
||||||
|
// ✅ Wrap in setState to update the UI
|
||||||
|
controllers["templateName"]?.text =
|
||||||
|
widget.templateData?["templateData"]?["template_name"] ?? "";
|
||||||
|
|
||||||
|
controllers["subject"]?.text =
|
||||||
|
widget.templateData?["templateData"]?["subject"] ?? "";
|
||||||
|
final bodyHtml =
|
||||||
|
widget.templateData?["templateData"]?["body_html"] ?? "";
|
||||||
|
|
||||||
|
print("bodyHtml - $bodyHtml");
|
||||||
|
|
||||||
|
String html = widget.templateData?["templateData"]?["body_html"] ?? "";
|
||||||
|
|
||||||
|
final htmlToDelta = HtmlToDelta();
|
||||||
|
|
||||||
|
// Convert the HTML string to Quill Delta format
|
||||||
|
// This is where the magic happens, but also where complex HTML might be simplified
|
||||||
|
final quill.Delta initialDelta = htmlToDelta.convert(html);
|
||||||
|
|
||||||
|
// Create a Quill Document from the Delta
|
||||||
|
final quill.Document quillDoc = quill.Document.fromDelta(initialDelta);
|
||||||
|
|
||||||
|
// Initialize the QuillController with the converted document
|
||||||
|
_controller = quill.QuillController(
|
||||||
|
document: quillDoc,
|
||||||
|
selection: const TextSelection.collapsed(
|
||||||
|
offset: 0,
|
||||||
|
), // Cursor at the start
|
||||||
|
);
|
||||||
|
|
||||||
|
// final plainText = extractPlainTextFromHtml(bodyHtml);
|
||||||
|
// final decodedText = decodeHtmlEntities(plainText);
|
||||||
|
// final quillDoc = quill.Document()..insert(0, decodedText);
|
||||||
|
// _controller = quill.QuillController(
|
||||||
|
// document: quillDoc,
|
||||||
|
// selection: const TextSelection.collapsed(offset: 0),
|
||||||
|
// );
|
||||||
|
|
||||||
|
templateName =
|
||||||
|
widget.templateData?["templateData"]?["template_name"] ?? "";
|
||||||
|
|
||||||
|
print("Fetched template_name: $templateName");
|
||||||
|
|
||||||
|
final rawPlaceholder =
|
||||||
|
widget.templateData?["templateData"]?["placeholder"];
|
||||||
|
|
||||||
|
if (rawPlaceholder is String) {
|
||||||
|
// If it's a JSON string, decode it first
|
||||||
|
placeholderList = List<Map<String, dynamic>>.from(
|
||||||
|
jsonDecode(rawPlaceholder),
|
||||||
|
);
|
||||||
|
} else if (rawPlaceholder is List) {
|
||||||
|
// If it's already a list (ideal case)
|
||||||
|
placeholderList = List<Map<String, dynamic>>.from(rawPlaceholder);
|
||||||
|
}
|
||||||
|
|
||||||
|
print("Extracted placeholders: $placeholders");
|
||||||
|
|
||||||
|
print("Fetched placeholders: $placeholderList");
|
||||||
|
|
||||||
|
templateId =
|
||||||
|
int.tryParse(
|
||||||
|
widget.templateData?["templateData"]?["template_id"]
|
||||||
|
?.toString() ??
|
||||||
|
'0',
|
||||||
|
) ??
|
||||||
|
0;
|
||||||
|
print("Fetched template_id: $templateId");
|
||||||
|
|
||||||
|
// if (widget.group?["international_policy_id"] != null) {
|
||||||
|
// selectedInternational =
|
||||||
|
// widget.group!["international_policy_id"].toString();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
print("API Selected User Has Data - No data available yet");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> handleSubmit() async {
|
||||||
|
Map<String, dynamic> data = TemplateData;
|
||||||
|
|
||||||
|
print('TemplateData - $data');
|
||||||
|
// final String deltaJsonString = TemplateData?["body_html"] ?? "[]";
|
||||||
|
//
|
||||||
|
// print('deltaJsonString $deltaJsonString');
|
||||||
|
//
|
||||||
|
// // Decode the JSON string into a list
|
||||||
|
// final List<dynamic> deltaJson = jsonDecode(deltaJsonString);
|
||||||
|
//
|
||||||
|
// print(DeltaToHTML.encodeJson(deltaJson));
|
||||||
|
//
|
||||||
|
// // Then convert it to a Quill document
|
||||||
|
// final doc = Document.fromJson(List<Map<String, dynamic>>.from(deltaJson));
|
||||||
|
//
|
||||||
|
// // Set it to the controller
|
||||||
|
// _controller = QuillController(
|
||||||
|
// document: doc,
|
||||||
|
// selection: const TextSelection.collapsed(offset: 0),
|
||||||
|
// );
|
||||||
|
// print('doc JSON: ${jsonEncode(doc.toDelta().toJson())}');
|
||||||
|
// print('doc plain text: ${doc.toPlainText()}');
|
||||||
|
// print('doc $doc');
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
updateTemplateData(data);
|
||||||
|
// This triggers UI rebuild with error messages
|
||||||
|
// if (validateData()) {
|
||||||
|
// postGroupData();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> updateTemplateData(policyData) async {
|
||||||
|
final String apiUrldata = '$apiUrl/api/template/update/${templateId}';
|
||||||
|
final token = await getToken(); // Fetch token
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
final response = await http.put(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: jsonEncode(policyData), // Convert map to JSON
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
print("policyData submitted successfully!");
|
||||||
|
print("Response: ${response.body}");
|
||||||
|
|
||||||
|
context.go('/templateList');
|
||||||
|
} else {
|
||||||
|
print("Failed to submit policyData. Status: ${response.statusCode}");
|
||||||
|
print("Error: ${response.body}");
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print(" Error submitting policyData: $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ResponsiveBuilder(
|
||||||
|
builder: (context, sizingInfo) {
|
||||||
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFFf5f5f5),
|
||||||
|
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||||
|
drawer: CustomDrawer(isDesktop: false),
|
||||||
|
body: Padding(
|
||||||
|
padding:
|
||||||
|
isDesktop
|
||||||
|
? EdgeInsets.symmetric(
|
||||||
|
horizontal:
|
||||||
|
MediaQuery.of(context).size.width *
|
||||||
|
0.1, // 30% of screen width as horizontal padding
|
||||||
|
vertical:
|
||||||
|
MediaQuery.of(context).size.height *
|
||||||
|
0, // 5% of screen height as vertical padding
|
||||||
|
)
|
||||||
|
: EdgeInsets.all(0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
|
Expanded(
|
||||||
|
child: buildUserTable(
|
||||||
|
isDesktop,
|
||||||
|
context,
|
||||||
|
bodyColor,
|
||||||
|
layoutColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildUserTable(
|
||||||
|
bool isDesktop,
|
||||||
|
context,
|
||||||
|
Color? bodyColor,
|
||||||
|
Color layoutColor,
|
||||||
|
) {
|
||||||
|
return Container(
|
||||||
|
margin: isDesktop ? const EdgeInsets.only(top: 5.0, bottom: 10.0) : null,
|
||||||
|
padding: const EdgeInsets.all(28),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
|
||||||
|
),
|
||||||
|
child: SafeArea(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
formatTemplateName(templateName),
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
// buildTempalteSubject(isDesktop),
|
||||||
|
//
|
||||||
|
// SizedBox(height: 10),
|
||||||
|
buildTempalteBody(isDesktop),
|
||||||
|
Spacer(),
|
||||||
|
buildActions(isDesktop),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTempalteSubject(bool isDesktop) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Subject",
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Color(0xFF575A74),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
CustomTextFieldUserTravellerWrapper(
|
||||||
|
isFocused: false,
|
||||||
|
color: Colors.white,
|
||||||
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
|
||||||
|
isDesktop: isDesktop,
|
||||||
|
child: SizedBox(
|
||||||
|
height: 40,
|
||||||
|
child: TextField(
|
||||||
|
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
|
controller: controllers["subject"],
|
||||||
|
onChanged: (value) {
|
||||||
|
// _clearError("local_id_num");
|
||||||
|
},
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Enter the subject",
|
||||||
|
labelStyle: GoogleFonts.poppins(
|
||||||
|
fontSize: 12,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
|
border: InputBorder.none,
|
||||||
|
contentPadding: EdgeInsets.symmetric(vertical: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTempalteBody(bool isDesktop) {
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// Text(
|
||||||
|
// "Content",
|
||||||
|
// style: GoogleFonts.poppins(
|
||||||
|
// fontSize: 12,
|
||||||
|
// fontWeight: FontWeight.w600,
|
||||||
|
// color: Color(0xFF575A74),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
Container(
|
||||||
|
color: Color(0xFFFFFEF0),
|
||||||
|
width: isDesktop ? MediaQuery.of(context).size.width * 0.8 : null,
|
||||||
|
child: IconTheme(
|
||||||
|
data: IconThemeData(size: 18), // Set icon size here
|
||||||
|
child: QuillSimpleToolbar(
|
||||||
|
controller: _controller,
|
||||||
|
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;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
Container(
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
final selected = await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder:
|
||||||
|
(context) =>
|
||||||
|
PlaceholdersModal(placeholders: placeholderList),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selected != null) {
|
||||||
|
print("User selected placeholder: $selected");
|
||||||
|
// You can now insert into a controller or editor
|
||||||
|
// Ensure the editor is focused
|
||||||
|
FocusScope.of(context).requestFocus(_focusNode);
|
||||||
|
|
||||||
|
final selection = _controller.selection;
|
||||||
|
final position = selection.baseOffset;
|
||||||
|
|
||||||
|
// if (position >= 0) {
|
||||||
|
// final intPosition = position.toInt();
|
||||||
|
//
|
||||||
|
// _controller.document.insert(intPosition, selected);
|
||||||
|
//
|
||||||
|
// _controller.updateSelection(
|
||||||
|
// TextSelection.collapsed(
|
||||||
|
// offset: intPosition + selected.length,
|
||||||
|
// ),
|
||||||
|
// ChangeSource.local,
|
||||||
|
// );
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
foregroundColor: Colors.grey,
|
||||||
|
// padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Placeholders',
|
||||||
|
style: GoogleFonts.poppins(fontSize: 13, color: Colors.black),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
height: MediaQuery.of(context).size.height * 0.5,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(color: Color(0xFFD6D5E6), width: 0.5),
|
||||||
|
),
|
||||||
|
child: QuillEditor(
|
||||||
|
controller: _controller,
|
||||||
|
scrollController: ScrollController(),
|
||||||
|
|
||||||
|
focusNode: _focusNode,
|
||||||
|
config: QuillEditorConfig(
|
||||||
|
placeholder: 'Start writing your notes...',
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
embedBuilders: [
|
||||||
|
...FlutterQuillEmbeds.editorBuilders(
|
||||||
|
imageEmbedConfig: QuillEditorImageEmbedConfig(
|
||||||
|
imageProviderBuilder: (context, imageUrl) {
|
||||||
|
// https://pub.dev/packages/flutter_quill_extensions#-image-assets
|
||||||
|
if (imageUrl.startsWith('assets/')) {
|
||||||
|
return AssetImage(imageUrl);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
videoEmbedConfig: QuillEditorVideoEmbedConfig(
|
||||||
|
customVideoBuilder: (videoUrl, readOnly) {
|
||||||
|
// To load YouTube videos https://github.com/singerdmx/flutter-quill/releases/tag/v10.8.0
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TimeStampEmbedBuilder(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildActions(bool isDesktop) {
|
||||||
|
return Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
context.go('/OrganizationSettings');
|
||||||
|
// You can get text from commentController.text
|
||||||
|
Navigator.of(context).pop(); // Close the modal
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
foregroundColor: layoutColor,
|
||||||
|
// backgroundColor: widget.layoutColor,
|
||||||
|
backgroundColor: Colors.white,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
side: BorderSide(color: layoutColor, width: 2),
|
||||||
|
),
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Cancel',
|
||||||
|
style: GoogleFonts.poppins(
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
color: layoutColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 10),
|
||||||
|
SizedBox(
|
||||||
|
child: ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
handleSubmit();
|
||||||
|
// You can get text from commentController.text
|
||||||
|
// Navigator.of(context).pop(); // Close the modal
|
||||||
|
},
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: layoutColor,
|
||||||
|
// backgroundColor: widget.layoutColor,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Text(
|
||||||
|
'Save',
|
||||||
|
style: GoogleFonts.poppins(fontSize: 14, color: Colors.white),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
_editorScrollController.dispose();
|
||||||
|
_editorFocusNode.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeStampEmbed extends Embeddable {
|
||||||
|
const TimeStampEmbed(String value) : super(timeStampType, value);
|
||||||
|
|
||||||
|
static const String timeStampType = 'timeStamp';
|
||||||
|
|
||||||
|
static TimeStampEmbed fromDocument(Document document) =>
|
||||||
|
TimeStampEmbed(jsonEncode(document.toDelta().toJson()));
|
||||||
|
|
||||||
|
Document get document => Document.fromJson(jsonDecode(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
class TimeStampEmbedBuilder extends EmbedBuilder {
|
||||||
|
@override
|
||||||
|
String get key => 'timeStamp';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toPlainText(Embed node) {
|
||||||
|
return node.value.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, EmbedContext embedContext) {
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.access_time_rounded),
|
||||||
|
Text(embedContext.node.value.data as String),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -10,6 +10,7 @@ import 'package:http/http.dart' as http;
|
|||||||
import 'package:http_parser/http_parser.dart';
|
import 'package:http_parser/http_parser.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
import '../../config/apiUrl.dart';
|
import '../../config/apiUrl.dart';
|
||||||
import '../../routes/custom_appBar.dart';
|
import '../../routes/custom_appBar.dart';
|
||||||
@ -66,11 +67,13 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
String? bodyStringColor = await getBodyColor();
|
String? bodyStringColor = await getBodyColor();
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
layoutColor = layoutString != null
|
layoutColor =
|
||||||
|
layoutString != null
|
||||||
? Color(int.parse(layoutString))
|
? Color(int.parse(layoutString))
|
||||||
: Colors.redAccent;
|
: Colors.redAccent;
|
||||||
|
|
||||||
bodyColor = bodyStringColor != null
|
bodyColor =
|
||||||
|
bodyStringColor != null
|
||||||
? Color(int.parse(bodyStringColor))
|
? Color(int.parse(bodyStringColor))
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
});
|
});
|
||||||
@ -99,7 +102,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
"created_by": null,
|
"created_by": null,
|
||||||
"updated_by": null,
|
"updated_by": null,
|
||||||
"is_active": 1
|
"is_active": 1,
|
||||||
|
|
||||||
// "org_id": orgId,
|
// "org_id": orgId,
|
||||||
// "created_by": userId,
|
// "created_by": userId,
|
||||||
@ -144,10 +147,14 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
try {
|
try {
|
||||||
print("getUpdatedServices");
|
print("getUpdatedServices");
|
||||||
|
|
||||||
final result = await apiService.fetchOrganization();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
print("UUPdatedServices - $result");
|
final String? orgDataString = prefs.getString('org_data');
|
||||||
|
|
||||||
|
if (orgDataString != null) {
|
||||||
|
final Map<String, dynamic> orgData = jsonDecode(orgDataString);
|
||||||
|
print("UUPdatedServices - $orgData");
|
||||||
setState(() {
|
setState(() {
|
||||||
selectedOrg = result;
|
selectedOrg = orgData;
|
||||||
|
|
||||||
String? rawLogoPath = selectedOrg?['logo'];
|
String? rawLogoPath = selectedOrg?['logo'];
|
||||||
if (rawLogoPath != null && rawLogoPath.contains('/assets')) {
|
if (rawLogoPath != null && rawLogoPath.contains('/assets')) {
|
||||||
@ -158,16 +165,27 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
_orgNameController.text = selectedOrg?['name'];
|
_orgNameController.text = selectedOrg?['name'];
|
||||||
|
|
||||||
layoutColor = selectedOrg?['layout_color'] != null
|
layoutColor =
|
||||||
? Color(int.parse(
|
selectedOrg?['layout_color'] != null
|
||||||
selectedOrg!['layout_color'].toString().replaceFirst('0x', ''),
|
? Color(
|
||||||
radix: 16))
|
int.parse(
|
||||||
|
selectedOrg!['layout_color'].toString().replaceFirst(
|
||||||
|
'0x',
|
||||||
|
'',
|
||||||
|
),
|
||||||
|
radix: 16,
|
||||||
|
),
|
||||||
|
)
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
|
|
||||||
bodyColor = selectedOrg?['color'] != null
|
bodyColor =
|
||||||
? Color(int.parse(
|
selectedOrg?['color'] != null
|
||||||
|
? Color(
|
||||||
|
int.parse(
|
||||||
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
||||||
radix: 16))
|
radix: 16,
|
||||||
|
),
|
||||||
|
)
|
||||||
: Colors.blue;
|
: Colors.blue;
|
||||||
|
|
||||||
// Set mail config fields
|
// Set mail config fields
|
||||||
@ -200,12 +218,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
services = [];
|
services = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedServiceIds = services.map<Map<String, dynamic>>((item) {
|
selectedServiceIds =
|
||||||
|
services.map<Map<String, dynamic>>((item) {
|
||||||
// force cast or copy to a regular map
|
// force cast or copy to a regular map
|
||||||
final map = Map<String, dynamic>.from(item);
|
final map = Map<String, dynamic>.from(item);
|
||||||
return {
|
return {"service_id": map['service_id'].toString()};
|
||||||
"service_id": map['service_id'].toString(),
|
|
||||||
};
|
|
||||||
}).toList();
|
}).toList();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -213,6 +230,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
print("selectedOrg - $selectedOrg");
|
print("selectedOrg - $selectedOrg");
|
||||||
print("mailConfig - $mailConfig");
|
print("mailConfig - $mailConfig");
|
||||||
|
}
|
||||||
|
|
||||||
|
// final result = await apiService.fetchOrganization();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error fetching updatedServices list: $e');
|
print('Error fetching updatedServices list: $e');
|
||||||
}
|
}
|
||||||
@ -222,10 +242,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
errorMessages.clear(); // Reset errors
|
errorMessages.clear(); // Reset errors
|
||||||
|
|
||||||
// Required fields that must not be empty
|
// Required fields that must not be empty
|
||||||
List<String> requiredFields = [
|
List<String> requiredFields = ["name", "description"];
|
||||||
"name",
|
|
||||||
"description",
|
|
||||||
];
|
|
||||||
|
|
||||||
// Check validation for each field
|
// Check validation for each field
|
||||||
for (String field in requiredFields) {
|
for (String field in requiredFields) {
|
||||||
@ -298,7 +315,26 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
if (response.statusCode == 200 || response.statusCode == 201) {
|
if (response.statusCode == 200 || response.statusCode == 201) {
|
||||||
print("✅ User submitted successfully!");
|
print("✅ User submitted successfully!");
|
||||||
print("📨 Response: ${response.body}");
|
print("📨 Response Organizt Update: ${response.body}");
|
||||||
|
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure each item is a Map<String, dynamic>
|
||||||
|
final Map<String, dynamic> orgList = Map<String, dynamic>.from(
|
||||||
|
data['data'],
|
||||||
|
);
|
||||||
|
|
||||||
|
print(orgList);
|
||||||
|
await updateOrgDataWithNewValues(orgList);
|
||||||
|
print("📨 Response Organizt Update:");
|
||||||
|
// return orgList;
|
||||||
|
|
||||||
context.go('/listPlan');
|
context.go('/listPlan');
|
||||||
} else {
|
} else {
|
||||||
print("❌ Submission failed. Status: ${response.statusCode}");
|
print("❌ Submission failed. Status: ${response.statusCode}");
|
||||||
@ -309,6 +345,27 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> updateOrgDataWithNewValues(Map<String, dynamic> newData) async {
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? orgDataString = prefs.getString('org_data');
|
||||||
|
|
||||||
|
Map<String, dynamic> orgData = {};
|
||||||
|
if (orgDataString != null) {
|
||||||
|
try {
|
||||||
|
orgData = jsonDecode(orgDataString);
|
||||||
|
} catch (e) {
|
||||||
|
print('❌ Failed to decode org_data: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge in the new data
|
||||||
|
orgData.addAll(newData);
|
||||||
|
|
||||||
|
// Save back
|
||||||
|
await prefs.setString('org_data', jsonEncode(orgData));
|
||||||
|
print("✅ Updated org_data saved.");
|
||||||
|
}
|
||||||
|
|
||||||
void handleSubmit() {
|
void handleSubmit() {
|
||||||
print("HandleSubmiy - $orgData");
|
print("HandleSubmiy - $orgData");
|
||||||
createOrgData(orgData);
|
createOrgData(orgData);
|
||||||
@ -327,8 +384,10 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
return ResponsiveBuilder(
|
||||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
builder: (context, sizingInfo) {
|
||||||
|
bool isDesktop =
|
||||||
|
sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
// backgroundColor: Colors.white,
|
// backgroundColor: Colors.white,
|
||||||
@ -336,23 +395,27 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||||
drawer: CustomDrawer(isDesktop: false),
|
drawer: CustomDrawer(isDesktop: false),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: isDesktop
|
padding:
|
||||||
|
isDesktop
|
||||||
? EdgeInsets.symmetric(
|
? EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width *
|
horizontal:
|
||||||
|
MediaQuery.of(context).size.width *
|
||||||
0.1, // 30% of screen width as horizontal padding
|
0.1, // 30% of screen width as horizontal padding
|
||||||
vertical: MediaQuery.of(context).size.height *
|
vertical:
|
||||||
|
MediaQuery.of(context).size.height *
|
||||||
0, // 5% of screen height as vertical padding
|
0, // 5% of screen height as vertical padding
|
||||||
)
|
)
|
||||||
: EdgeInsets.all(0),
|
: EdgeInsets.all(0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||||
Expanded(child: buildOrganizationLayout(isDesktop))
|
Expanded(child: buildOrganizationLayout(isDesktop)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildOrganizationLayout(isDesktop) {
|
Widget buildOrganizationLayout(isDesktop) {
|
||||||
@ -382,18 +445,26 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(5),
|
padding: const EdgeInsets.all(5),
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: isDesktop
|
child:
|
||||||
|
isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
// children: [Text("Button")],
|
// children: [Text("Button")],
|
||||||
children:
|
children: _buildSubmit(
|
||||||
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
isDesktop,
|
||||||
|
isViewMode,
|
||||||
|
layoutColor,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
: Row(
|
: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children:
|
children: _buildSubmit(
|
||||||
_buildSubmit(isDesktop, isViewMode, layoutColor),
|
isDesktop,
|
||||||
))
|
isViewMode,
|
||||||
|
layoutColor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -402,8 +473,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
Widget buildOrgLayout(bool isDesktop) {
|
Widget buildOrgLayout(bool isDesktop) {
|
||||||
Future<void> _pickImage() async {
|
Future<void> _pickImage() async {
|
||||||
final picker = ImagePicker();
|
final picker = ImagePicker();
|
||||||
final XFile? pickedFile =
|
final XFile? pickedFile = await picker.pickImage(
|
||||||
await picker.pickImage(source: ImageSource.gallery);
|
source: ImageSource.gallery,
|
||||||
|
);
|
||||||
|
|
||||||
if (pickedFile != null && kIsWeb) {
|
if (pickedFile != null && kIsWeb) {
|
||||||
try {
|
try {
|
||||||
@ -424,7 +496,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
// margin: isDesktop
|
// margin: isDesktop
|
||||||
// ? EdgeInsets.all(10.0)
|
// ? EdgeInsets.all(10.0)
|
||||||
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
// : EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||||
height: isDesktop
|
height:
|
||||||
|
isDesktop
|
||||||
? MediaQuery.of(context).size.height * 0.98
|
? MediaQuery.of(context).size.height * 0.98
|
||||||
: MediaQuery.of(context).size.height,
|
: MediaQuery.of(context).size.height,
|
||||||
// decoration: BoxDecoration(
|
// decoration: BoxDecoration(
|
||||||
@ -446,7 +519,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 20, right: 20, bottom: 20, top: 5),
|
left: 20,
|
||||||
|
right: 20,
|
||||||
|
bottom: 20,
|
||||||
|
top: 5,
|
||||||
|
),
|
||||||
// height: MediaQuery.of(context).size.height * 0.8,
|
// height: MediaQuery.of(context).size.height * 0.8,
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -463,7 +540,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
? "Update Organization"
|
? "Update Organization"
|
||||||
: "Create Organization",
|
: "Create Organization",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 15, fontWeight: FontWeight.w500),
|
fontSize: 15,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -472,7 +551,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
crossAxisAlignment: CrossAxisAlignment.center, // now -> .center , old -> .start
|
crossAxisAlignment:
|
||||||
|
CrossAxisAlignment
|
||||||
|
.center, // now -> .center , old -> .start
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(top: 1.0),
|
padding: const EdgeInsets.only(top: 1.0),
|
||||||
@ -481,7 +562,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
@ -496,7 +578,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Enter Organization Name",
|
hintText: "Enter Organization Name",
|
||||||
hintStyle: GoogleFonts.poppins(
|
hintStyle: GoogleFonts.poppins(
|
||||||
fontSize: 14, color: Colors.grey),
|
fontSize: 14,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
floatingLabelBehavior:
|
floatingLabelBehavior:
|
||||||
FloatingLabelBehavior.never,
|
FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
@ -510,7 +594,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
Spacer(),
|
Spacer(),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: _pickImage,
|
onTap: _pickImage,
|
||||||
child: _imageBytes != null
|
child:
|
||||||
|
_imageBytes != null
|
||||||
? ClipOval(
|
? ClipOval(
|
||||||
child: Image.memory(
|
child: Image.memory(
|
||||||
_imageBytes!,
|
_imageBytes!,
|
||||||
@ -527,8 +612,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
height: 75, // increased
|
height: 75, // increased
|
||||||
|
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder:
|
errorBuilder: (
|
||||||
(context, error, stackTrace) {
|
context,
|
||||||
|
error,
|
||||||
|
stackTrace,
|
||||||
|
) {
|
||||||
return const CircleAvatar(
|
return const CircleAvatar(
|
||||||
radius: 20,
|
radius: 20,
|
||||||
backgroundColor: Colors.redAccent,
|
backgroundColor: Colors.redAccent,
|
||||||
@ -547,30 +635,33 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(height: 10),
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
"Services",
|
"Services",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121),
|
||||||
),
|
),
|
||||||
SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
border: Border.all(color: Color(0xFFF4F4FB)),
|
border: Border.all(color: Color(0xFFF4F4FB)),
|
||||||
borderRadius: BorderRadius.circular(1),
|
borderRadius: BorderRadius.circular(1),
|
||||||
// color: bodyColor,
|
// color: bodyColor,
|
||||||
// color: Color(0xFFF5F5F5),
|
// color: Color(0xFFF5F5F5),
|
||||||
color: Colors.white),
|
color: Colors.white,
|
||||||
padding:
|
),
|
||||||
EdgeInsets.only(left: 5, right: 5, top: 15, bottom: 5),
|
padding: EdgeInsets.only(
|
||||||
child: isDesktop
|
left: 5,
|
||||||
|
right: 5,
|
||||||
|
top: 15,
|
||||||
|
bottom: 5,
|
||||||
|
),
|
||||||
|
child:
|
||||||
|
isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||||
// mainAxisSize: MainAxisSize.min,
|
// mainAxisSize: MainAxisSize.min,
|
||||||
@ -579,15 +670,11 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
: Expanded(
|
: Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Row(
|
child: Row(children: _buildOptions()),
|
||||||
children: _buildOptions(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
SizedBox(height: 15),
|
||||||
SizedBox(
|
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -597,7 +684,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -606,18 +694,26 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
// color: Color(0xFFF4F4FB),
|
// color: Color(0xFFF4F4FB),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(
|
||||||
left: 5, right: 5, top: 15, bottom: 5),
|
left: 5,
|
||||||
child: layoutColor != null && bodyColor != null
|
right: 5,
|
||||||
|
top: 15,
|
||||||
|
bottom: 5,
|
||||||
|
),
|
||||||
|
child:
|
||||||
|
layoutColor != null && bodyColor != null
|
||||||
? ColorThemePickerWidget(
|
? ColorThemePickerWidget(
|
||||||
initialLayoutColor: layoutColor,
|
initialLayoutColor: layoutColor,
|
||||||
initialBodyColor: bodyColor,
|
initialBodyColor: bodyColor,
|
||||||
onLayoutColorSelected:
|
onLayoutColorSelected: (
|
||||||
(Color selectedLayoutColor) {
|
Color selectedLayoutColor,
|
||||||
|
) {
|
||||||
setState(() {
|
setState(() {
|
||||||
layoutColor = selectedLayoutColor;
|
layoutColor = selectedLayoutColor;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onBodyColorSelected: (Color selectedBodyColor) {
|
onBodyColorSelected: (
|
||||||
|
Color selectedBodyColor,
|
||||||
|
) {
|
||||||
setState(() {
|
setState(() {
|
||||||
bodyColor = selectedBodyColor;
|
bodyColor = selectedBodyColor;
|
||||||
});
|
});
|
||||||
@ -628,9 +724,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
SizedBox(
|
SizedBox(height: 15),
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
Container(
|
Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -643,7 +737,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF212121)),
|
color: Color(0xFF212121),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// GestureDetector(
|
// GestureDetector(
|
||||||
@ -660,11 +755,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
// ),
|
// ),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
// if (showMail)
|
|
||||||
|
|
||||||
SizedBox(
|
// if (showMail)
|
||||||
height: 10,
|
SizedBox(height: 10),
|
||||||
),
|
|
||||||
Container(
|
Container(
|
||||||
// width: double.infinity,
|
// width: double.infinity,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -678,7 +771,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
// color: Color(0xFFF5F5F5),
|
// color: Color(0xFFF5F5F5),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment: isDesktop
|
mainAxisAlignment:
|
||||||
|
isDesktop
|
||||||
? MainAxisAlignment.start
|
? MainAxisAlignment.start
|
||||||
: MainAxisAlignment.center,
|
: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
@ -688,17 +782,18 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
initialMailData: mailConfig,
|
initialMailData: mailConfig,
|
||||||
onMailDataChanged: (updatedData) {
|
onMailDataChanged: (updatedData) {
|
||||||
// You can setState here or do something else with updatedData
|
// You can setState here or do something else with updatedData
|
||||||
print(
|
print("Updated Mail Data: $updatedData");
|
||||||
"Updated Mail Data: $updatedData");
|
|
||||||
|
|
||||||
mailConfig = updatedData;
|
mailConfig = updatedData;
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
: CircularProgressIndicator(),
|
: CircularProgressIndicator(),
|
||||||
],
|
],
|
||||||
))
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
// isDesktop
|
// isDesktop
|
||||||
// ? Row(
|
// ? Row(
|
||||||
// mainAxisAlignment: MainAxisAlignment.end,
|
// mainAxisAlignment: MainAxisAlignment.end,
|
||||||
@ -738,8 +833,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
|
|
||||||
String serviceId = service['service_id'].toString();
|
String serviceId = service['service_id'].toString();
|
||||||
// bool isSelected = selectedServiceIds.contains(serviceId);
|
// bool isSelected = selectedServiceIds.contains(serviceId);
|
||||||
bool isSelected =
|
bool isSelected = selectedServiceIds.any(
|
||||||
selectedServiceIds.any((item) => item["service_id"] == serviceId);
|
(item) => item["service_id"] == serviceId,
|
||||||
|
);
|
||||||
|
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
@ -747,8 +843,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
String serviceId = service['service_id'].toString();
|
String serviceId = service['service_id'].toString();
|
||||||
|
|
||||||
// Check if already selected
|
// Check if already selected
|
||||||
int existingIndex = selectedServiceIds
|
int existingIndex = selectedServiceIds.indexWhere(
|
||||||
.indexWhere((item) => item["service_id"] == serviceId);
|
(item) => item["service_id"] == serviceId,
|
||||||
|
);
|
||||||
|
|
||||||
if (existingIndex != -1) {
|
if (existingIndex != -1) {
|
||||||
selectedServiceIds.removeAt(existingIndex);
|
selectedServiceIds.removeAt(existingIndex);
|
||||||
@ -757,24 +854,30 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
child: Row(children: [
|
child: Row(
|
||||||
|
children: [
|
||||||
iconUrl.isNotEmpty
|
iconUrl.isNotEmpty
|
||||||
? Image.network(
|
? Image.network(
|
||||||
iconUrl,
|
iconUrl,
|
||||||
width: 18,
|
width: 18,
|
||||||
height: 18,
|
height: 18,
|
||||||
errorBuilder: (context, error, stackTrace) {
|
errorBuilder: (context, error, stackTrace) {
|
||||||
return Icon(fallbackIcon,
|
return Icon(
|
||||||
size: 18,
|
fallbackIcon,
|
||||||
color: isSelected == name
|
|
||||||
? Color(0xFF114D8B)
|
|
||||||
: Color(0xFF475569));
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: Icon(fallbackIcon,
|
|
||||||
size: 18,
|
size: 18,
|
||||||
color:
|
color:
|
||||||
isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569)),
|
isSelected == name
|
||||||
|
? Color(0xFF114D8B)
|
||||||
|
: Color(0xFF475569),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)
|
||||||
|
: Icon(
|
||||||
|
fallbackIcon,
|
||||||
|
size: 18,
|
||||||
|
color:
|
||||||
|
isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(width: 2),
|
SizedBox(width: 2),
|
||||||
|
|
||||||
@ -784,7 +887,8 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
|
color: isSelected == name ? Color(0xFF114D8B) : Color(0xFF475569),
|
||||||
fontWeight:
|
fontWeight:
|
||||||
isSelected == name ? FontWeight.bold : FontWeight.w500),
|
isSelected == name ? FontWeight.bold : FontWeight.w500,
|
||||||
|
),
|
||||||
// fontWeight: selectedListOption == title ? FontWeight.bold : FontWeight.normal,)),
|
// fontWeight: selectedListOption == title ? FontWeight.bold : FontWeight.normal,)),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -796,15 +900,19 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isSelected ? Colors.green : Colors.grey, width: 1),
|
color: isSelected ? Colors.green : Colors.grey,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
Icons.check_circle,
|
Icons.check_circle,
|
||||||
size: 10,
|
size: 10,
|
||||||
color: isSelected ? Colors.green : Colors.grey,
|
color: isSelected ? Colors.green : Colors.grey,
|
||||||
// color: Colors.grey,
|
// color: Colors.grey,
|
||||||
)),
|
),
|
||||||
]),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,13 +956,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
context.go('/listPlan');
|
context.go('/listPlan');
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text("Cancel", style: GoogleFonts.poppins(fontSize: 12)),
|
||||||
"Cancel",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12),
|
|
||||||
)),
|
|
||||||
SizedBox(
|
|
||||||
width: 20,
|
|
||||||
),
|
),
|
||||||
|
SizedBox(width: 20),
|
||||||
MouseRegion(
|
MouseRegion(
|
||||||
// cursor: widget.isViewMode
|
// cursor: widget.isViewMode
|
||||||
// ? SystemMouseCursors.forbidden
|
// ? SystemMouseCursors.forbidden
|
||||||
@ -873,12 +977,9 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
|||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: handleSubmit, // Disable when in view mode
|
onPressed: handleSubmit, // Disable when in view mode
|
||||||
child: Text(
|
child: Text("Submit", style: GoogleFonts.poppins(fontSize: 12)),
|
||||||
"Submit",
|
|
||||||
style: GoogleFonts.poppins(fontSize: 12),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -125,7 +125,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
"employeeCode",
|
"employeeCode",
|
||||||
"dateOfIssue",
|
"dateOfIssue",
|
||||||
"dateOfExpiry",
|
"dateOfExpiry",
|
||||||
"changePassword"
|
"changePassword",
|
||||||
];
|
];
|
||||||
|
|
||||||
Color? layoutColor;
|
Color? layoutColor;
|
||||||
@ -197,7 +197,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
// apiUserData = users;
|
// apiUserData = users;
|
||||||
|
|
||||||
print("Total users fetched from API: ${users.length}");
|
print("Total users fetched from API: ${users.length}");
|
||||||
|
// user["role_id"] != "5" - Travel Agent
|
||||||
apiUserData = users.where((user) => user["role_id"] != "5").toList();
|
apiUserData = users.where((user) => user["role_id"] != "5").toList();
|
||||||
print("Total users fetched from API1: ${apiUserData?.length}");
|
print("Total users fetched from API1: ${apiUserData?.length}");
|
||||||
print("APIUSerDATa - $apiUserData");
|
print("APIUSerDATa - $apiUserData");
|
||||||
@ -206,7 +206,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
userMap = {
|
userMap = {
|
||||||
for (var user in userList)
|
for (var user in userList)
|
||||||
user['user_id'].toString():
|
user['user_id'].toString():
|
||||||
"${user['first_name']} ${user['last_name']}"
|
"${user['first_name']} ${user['last_name']}",
|
||||||
};
|
};
|
||||||
userIdsApi = userMap.keys.toList();
|
userIdsApi = userMap.keys.toList();
|
||||||
});
|
});
|
||||||
@ -240,7 +240,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
|
|
||||||
groupMap = {
|
groupMap = {
|
||||||
for (var group in groupList)
|
for (var group in groupList)
|
||||||
group['group_id'].toString(): group['name'].toString().trim()
|
group['group_id'].toString(): group['name'].toString().trim(),
|
||||||
};
|
};
|
||||||
|
|
||||||
userIdsApi = groupMap.keys.toList();
|
userIdsApi = groupMap.keys.toList();
|
||||||
@ -265,23 +265,12 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(height: 10),
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
_buildFirstRow(widget.isDesktop),
|
_buildFirstRow(widget.isDesktop),
|
||||||
if (widget.isDesktop)
|
if (widget.isDesktop) SizedBox(height: 10),
|
||||||
SizedBox(
|
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
_buildSecondRow(widget.isDesktop),
|
_buildSecondRow(widget.isDesktop),
|
||||||
if (widget.isDesktop)
|
if (widget.isDesktop) SizedBox(height: 10),
|
||||||
SizedBox(
|
Divider(thickness: 0.2, color: Colors.blueGrey.shade100),
|
||||||
height: 10,
|
|
||||||
),
|
|
||||||
Divider(
|
|
||||||
thickness: 0.2,
|
|
||||||
color: Colors.blueGrey.shade100,
|
|
||||||
),
|
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
@ -294,9 +283,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(height: 15),
|
||||||
height: 15,
|
|
||||||
),
|
|
||||||
_buildThirdRow(widget.isDesktop),
|
_buildThirdRow(widget.isDesktop),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -306,7 +293,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
Widget _buildFirstRow(bool isDesktop) {
|
Widget _buildFirstRow(bool isDesktop) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: widget.isDesktop
|
child:
|
||||||
|
widget.isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -333,7 +321,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
Widget _buildSecondRow(bool isDesktop) {
|
Widget _buildSecondRow(bool isDesktop) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: widget.isDesktop
|
child:
|
||||||
|
widget.isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -360,7 +349,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
Widget _buildThirdRow(bool isDesktop) {
|
Widget _buildThirdRow(bool isDesktop) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: widget.isDesktop
|
child:
|
||||||
|
widget.isDesktop
|
||||||
? Row(
|
? Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -369,10 +359,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
buildDelegationStartDateField(isDesktop),
|
buildDelegationStartDateField(isDesktop),
|
||||||
Spacer(), // Space after Last Name
|
Spacer(), // Space after Last Name
|
||||||
buildDelegationEndDateField(isDesktop),
|
buildDelegationEndDateField(isDesktop),
|
||||||
SizedBox(
|
SizedBox(width: 15),
|
||||||
width: 15,
|
buildReset(isDesktop),
|
||||||
),
|
|
||||||
buildReset(isDesktop)
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: Column(
|
: Column(
|
||||||
@ -383,7 +371,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
buildDelegationStartDateField(isDesktop),
|
buildDelegationStartDateField(isDesktop),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
buildDelegationEndDateField(isDesktop),
|
buildDelegationEndDateField(isDesktop),
|
||||||
buildReset(isDesktop)
|
buildReset(isDesktop),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -398,7 +386,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -415,8 +404,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Employee Code",
|
labelText: "Employee Code",
|
||||||
labelStyle:
|
labelStyle: GoogleFonts.poppins(
|
||||||
GoogleFonts.poppins(fontSize: 12, color: Colors.grey),
|
fontSize: 12,
|
||||||
|
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),
|
||||||
@ -444,7 +435,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -458,10 +450,12 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
style: GoogleFonts.poppins(fontSize: 12, color: Colors.black),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10), // Proper padding
|
horizontal: 10,
|
||||||
|
), // Proper padding
|
||||||
),
|
),
|
||||||
onChanged: widget.isViewMode
|
onChanged:
|
||||||
|
widget.isViewMode
|
||||||
? null
|
? null
|
||||||
: (newValue) {
|
: (newValue) {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -469,7 +463,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
});
|
});
|
||||||
widget.onDepartmentChanged?.call(newValue);
|
widget.onDepartmentChanged?.call(newValue);
|
||||||
},
|
},
|
||||||
items: apiCostData?.map<DropdownMenuItem<String>>((item) {
|
items:
|
||||||
|
apiCostData?.map<DropdownMenuItem<String>>((item) {
|
||||||
return DropdownMenuItem(
|
return DropdownMenuItem(
|
||||||
value: item['department_id'], // ID as value
|
value: item['department_id'], // ID as value
|
||||||
child: Text(item['name'] ?? "Unknown"),
|
child: Text(item['name'] ?? "Unknown"),
|
||||||
@ -496,9 +491,11 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
// isFocused: false,
|
// isFocused: false,
|
||||||
// isDesktop: widget.isDesktop,
|
// isDesktop: widget.isDesktop,
|
||||||
@ -542,13 +539,13 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
|
|
||||||
CustomTextFieldUserWrapper(
|
CustomTextFieldUserWrapper(
|
||||||
isFocused: false,
|
isFocused: false,
|
||||||
isDesktop: widget.isDesktop,
|
isDesktop: widget.isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: apiAllGroups == null
|
child:
|
||||||
|
apiAllGroups == null
|
||||||
? Center(
|
? Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
@ -566,41 +563,44 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search Group...",
|
hintText: "Search Group...",
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: 10),
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
|
||||||
// items: apiAllGroups!.map((group) {
|
// items: apiAllGroups!.map((group) {
|
||||||
// return "${group['name']} ";
|
// return "${group['name']} ";
|
||||||
// }).toList(),
|
// }).toList(),
|
||||||
|
items:
|
||||||
items: apiAllGroups!.map((group) {
|
apiAllGroups!.map((group) {
|
||||||
return group['name'].toString().trim(); // <-- trim spaces
|
return group['name']
|
||||||
|
.toString()
|
||||||
|
.trim(); // <-- trim spaces
|
||||||
}).toList(),
|
}).toList(),
|
||||||
|
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
dropdownSearchDecoration: InputDecoration(
|
dropdownSearchDecoration: InputDecoration(
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: EdgeInsets.symmetric(
|
contentPadding: EdgeInsets.symmetric(horizontal: 1),
|
||||||
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(
|
style: GoogleFonts.poppins(fontSize: 12),
|
||||||
fontSize: 12,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == null) return;
|
if (newValue == null) return;
|
||||||
|
|
||||||
final levelId = groupMap.entries
|
final levelId =
|
||||||
|
groupMap.entries
|
||||||
.firstWhere((entry) => entry.value == newValue)
|
.firstWhere((entry) => entry.value == newValue)
|
||||||
.key;
|
.key;
|
||||||
|
|
||||||
@ -608,8 +608,9 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
selectedLevel = levelId;
|
selectedLevel = levelId;
|
||||||
});
|
});
|
||||||
|
|
||||||
widget.onLevelChanged
|
widget.onLevelChanged?.call(
|
||||||
?.call(levelId); // ✅ pass the ID not the name
|
levelId,
|
||||||
|
); // ✅ pass the ID not the name
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -636,8 +637,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -645,7 +646,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: apiUserData == null
|
child:
|
||||||
|
apiUserData == null
|
||||||
? Center(
|
? Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
@ -662,12 +664,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search User...",
|
hintText: "Search User...",
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10),
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
items: apiUserData!.map((user) {
|
),
|
||||||
|
items:
|
||||||
|
apiUserData!.map((user) {
|
||||||
return "${user['first_name']} ${user['last_name']}";
|
return "${user['first_name']} ${user['last_name']}";
|
||||||
}).toList(),
|
}).toList(),
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
@ -678,7 +682,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align(
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
// Center-align selected item
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -688,6 +693,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// onChanged: (String? newValue) {
|
// onChanged: (String? newValue) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
// selectedFirstApprover = userMap.entries
|
// selectedFirstApprover = userMap.entries
|
||||||
@ -701,13 +707,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
// });
|
// });
|
||||||
// widget.onFirstApproverChanged?.call(newValue);
|
// widget.onFirstApproverChanged?.call(newValue);
|
||||||
// },
|
// },
|
||||||
|
|
||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == null) return;
|
if (newValue == null) return;
|
||||||
|
|
||||||
final approverId = userMap.entries
|
final approverId =
|
||||||
|
userMap.entries
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(entry) => entry.value == newValue)
|
(entry) => entry.value == newValue,
|
||||||
|
)
|
||||||
.key;
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -715,7 +722,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.onFirstApproverChanged?.call(
|
widget.onFirstApproverChanged?.call(
|
||||||
approverId); // ✅ not newValue, but approverId
|
approverId,
|
||||||
|
); // ✅ not newValue, but approverId
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -749,8 +757,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -758,7 +766,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: apiUserData == null
|
child:
|
||||||
|
apiUserData == null
|
||||||
? Center(
|
? Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
@ -775,12 +784,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search User...",
|
hintText: "Search User...",
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10),
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
items: apiUserData!.map((user) {
|
),
|
||||||
|
items:
|
||||||
|
apiUserData!.map((user) {
|
||||||
return "${user['first_name']} ${user['last_name']}";
|
return "${user['first_name']} ${user['last_name']}";
|
||||||
}).toList(),
|
}).toList(),
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
@ -791,7 +802,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align(
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
// Center-align selected item
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -805,9 +817,11 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == null) return;
|
if (newValue == null) return;
|
||||||
|
|
||||||
final approverId = userMap.entries
|
final approverId =
|
||||||
|
userMap.entries
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(entry) => entry.value == newValue)
|
(entry) => entry.value == newValue,
|
||||||
|
)
|
||||||
.key;
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -815,7 +829,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.onSecondApproverChanged?.call(
|
widget.onSecondApproverChanged?.call(
|
||||||
approverId); // ✅ not newValue, but approverId
|
approverId,
|
||||||
|
); // ✅ not newValue, but approverId
|
||||||
},
|
},
|
||||||
// onChanged: (String? newValue) {
|
// onChanged: (String? newValue) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
@ -845,9 +860,9 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
Widget buildApprover3(bool isDesktop) {
|
Widget buildApprover3(bool isDesktop) {
|
||||||
return Container(
|
return Container(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
|
|
||||||
// child: Expanded(
|
// child: Expanded(
|
||||||
// Allow second column to take available space
|
// Allow second column to take available space
|
||||||
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@ -861,8 +876,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -870,7 +885,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: apiUserData == null
|
child:
|
||||||
|
apiUserData == null
|
||||||
? Center(
|
? Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
@ -887,12 +903,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search User...",
|
hintText: "Search User...",
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10),
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
items: apiUserData!.map((user) {
|
),
|
||||||
|
items:
|
||||||
|
apiUserData!.map((user) {
|
||||||
return "${user['first_name']} ${user['last_name']}";
|
return "${user['first_name']} ${user['last_name']}";
|
||||||
}).toList(),
|
}).toList(),
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
@ -903,7 +921,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align(
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
// Center-align selected item
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -916,9 +935,11 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == null) return;
|
if (newValue == null) return;
|
||||||
|
|
||||||
final approverId = userMap.entries
|
final approverId =
|
||||||
|
userMap.entries
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(entry) => entry.value == newValue)
|
(entry) => entry.value == newValue,
|
||||||
|
)
|
||||||
.key;
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -926,7 +947,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.onThirdApproverChanged?.call(
|
widget.onThirdApproverChanged?.call(
|
||||||
approverId); // ✅ not newValue, but approverId
|
approverId,
|
||||||
|
); // ✅ not newValue, but approverId
|
||||||
},
|
},
|
||||||
// onChanged: (String? newValue) {
|
// onChanged: (String? newValue) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
@ -972,8 +994,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -981,7 +1003,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
isDesktop: isDesktop,
|
isDesktop: isDesktop,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
height: 40,
|
height: 40,
|
||||||
child: apiUserData == null
|
child:
|
||||||
|
apiUserData == null
|
||||||
? Center(
|
? Center(
|
||||||
child: Transform.scale(
|
child: Transform.scale(
|
||||||
scale: 0.5,
|
scale: 0.5,
|
||||||
@ -990,7 +1013,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
)
|
)
|
||||||
: DropdownSearch<String>(
|
: DropdownSearch<String>(
|
||||||
// selectedItem: userMap[selectedSubstituteApprover],
|
// selectedItem: userMap[selectedSubstituteApprover],
|
||||||
selectedItem: selectedSubstituteApprover != null
|
selectedItem:
|
||||||
|
selectedSubstituteApprover != null
|
||||||
? userMap[selectedSubstituteApprover]
|
? userMap[selectedSubstituteApprover]
|
||||||
: null,
|
: null,
|
||||||
enabled: !widget.isViewMode,
|
enabled: !widget.isViewMode,
|
||||||
@ -1001,12 +1025,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
searchFieldProps: TextFieldProps(
|
searchFieldProps: TextFieldProps(
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "Search User...",
|
hintText: "Search User...",
|
||||||
contentPadding:
|
contentPadding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 10),
|
horizontal: 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
items: apiUserData!.map((user) {
|
),
|
||||||
|
items:
|
||||||
|
apiUserData!.map((user) {
|
||||||
return "${user['first_name']} ${user['last_name']}";
|
return "${user['first_name']} ${user['last_name']}";
|
||||||
}).toList(),
|
}).toList(),
|
||||||
dropdownDecoratorProps: DropDownDecoratorProps(
|
dropdownDecoratorProps: DropDownDecoratorProps(
|
||||||
@ -1017,7 +1043,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
dropdownBuilder: (context, selectedItem) => Align(
|
dropdownBuilder:
|
||||||
|
(context, selectedItem) => Align(
|
||||||
// Center-align selected item
|
// Center-align selected item
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -1027,6 +1054,7 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// onChanged: (String? newValue) {
|
// onChanged: (String? newValue) {
|
||||||
// setState(() {
|
// setState(() {
|
||||||
// selectedFirstApprover = userMap.entries
|
// selectedFirstApprover = userMap.entries
|
||||||
@ -1040,13 +1068,14 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
// });
|
// });
|
||||||
// widget.onFirstApproverChanged?.call(newValue);
|
// widget.onFirstApproverChanged?.call(newValue);
|
||||||
// },
|
// },
|
||||||
|
|
||||||
onChanged: (String? newValue) {
|
onChanged: (String? newValue) {
|
||||||
if (newValue == null) return;
|
if (newValue == null) return;
|
||||||
|
|
||||||
final approverId = userMap.entries
|
final approverId =
|
||||||
|
userMap.entries
|
||||||
.firstWhere(
|
.firstWhere(
|
||||||
(entry) => entry.value == newValue)
|
(entry) => entry.value == newValue,
|
||||||
|
)
|
||||||
.key;
|
.key;
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -1054,7 +1083,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
widget.onFirstSubsApproverChanged?.call(
|
widget.onFirstSubsApproverChanged?.call(
|
||||||
approverId); // ✅ not newValue, but approverId
|
approverId,
|
||||||
|
); // ✅ not newValue, but approverId
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1095,7 +1125,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedCheckOutDate != null &&
|
initialDate:
|
||||||
|
_selectedCheckOutDate != null &&
|
||||||
_selectedCheckOutDate!.isAfter(today)
|
_selectedCheckOutDate!.isAfter(today)
|
||||||
? _selectedCheckOutDate!
|
? _selectedCheckOutDate!
|
||||||
: today,
|
: today,
|
||||||
@ -1106,8 +1137,9 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
if (pickedDate != null && pickedDate != _selectedCheckOutDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedCheckOutDate = pickedDate;
|
_selectedCheckOutDate = pickedDate;
|
||||||
widget.controllers["delegationStartDate"]?.text =
|
widget.controllers["delegationStartDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(pickedDate);
|
||||||
|
|
||||||
if (_selectedEndDate != null &&
|
if (_selectedEndDate != null &&
|
||||||
_selectedEndDate!.isBefore(_selectedCheckOutDate!)) {
|
_selectedEndDate!.isBefore(_selectedCheckOutDate!)) {
|
||||||
@ -1126,8 +1158,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -1149,13 +1181,18 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Select Date",
|
labelText: "Select Date",
|
||||||
labelStyle:
|
labelStyle: const TextStyle(
|
||||||
const TextStyle(fontSize: 12, color: Colors.grey),
|
fontSize: 12,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon: const Icon(Icons.calendar_today,
|
suffixIcon: const Icon(
|
||||||
size: 16, color: Colors.grey),
|
Icons.calendar_today,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1179,9 +1216,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
DateTime now = DateTime.now();
|
DateTime now = DateTime.now();
|
||||||
DateTime today = DateTime(now.year, now.month, now.day);
|
DateTime today = DateTime(now.year, now.month, now.day);
|
||||||
|
|
||||||
DateTime minDate = _selectedCheckOutDate != null
|
DateTime minDate =
|
||||||
? _selectedCheckOutDate!
|
_selectedCheckOutDate != null ? _selectedCheckOutDate! : today;
|
||||||
: today;
|
|
||||||
|
|
||||||
// Parse date from notifier if available, else use today
|
// Parse date from notifier if available, else use today
|
||||||
DateTime initialDate;
|
DateTime initialDate;
|
||||||
@ -1198,8 +1234,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
|
|
||||||
DateTime? pickedDate = await showDatePicker(
|
DateTime? pickedDate = await showDatePicker(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedEndDate != null &&
|
initialDate:
|
||||||
_selectedEndDate!.isAfter(minDate)
|
_selectedEndDate != null && _selectedEndDate!.isAfter(minDate)
|
||||||
? _selectedEndDate!
|
? _selectedEndDate!
|
||||||
: minDate,
|
: minDate,
|
||||||
firstDate: minDate,
|
firstDate: minDate,
|
||||||
@ -1209,8 +1245,9 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
if (pickedDate != null && pickedDate != _selectedEndDate) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedEndDate = pickedDate;
|
_selectedEndDate = pickedDate;
|
||||||
widget.controllers["delegationEndDate"]?.text =
|
widget.controllers["delegationEndDate"]?.text = DateFormat(
|
||||||
DateFormat('dd-MM-yyyy').format(pickedDate);
|
'dd-MM-yyyy',
|
||||||
|
).format(pickedDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1223,8 +1260,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
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(
|
||||||
@ -1247,13 +1284,18 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
style: const TextStyle(fontSize: 12),
|
style: const TextStyle(fontSize: 12),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
labelText: "Select Date",
|
labelText: "Select Date",
|
||||||
labelStyle:
|
labelStyle: const TextStyle(
|
||||||
const TextStyle(fontSize: 12, color: Colors.grey),
|
fontSize: 12,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
floatingLabelBehavior: FloatingLabelBehavior.never,
|
floatingLabelBehavior: FloatingLabelBehavior.never,
|
||||||
border: InputBorder.none,
|
border: InputBorder.none,
|
||||||
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
contentPadding: const EdgeInsets.symmetric(vertical: 16),
|
||||||
suffixIcon: const Icon(Icons.calendar_today,
|
suffixIcon: const Icon(
|
||||||
size: 16, color: Colors.grey),
|
Icons.calendar_today,
|
||||||
|
size: 16,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -1279,7 +1321,10 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
Text(
|
Text(
|
||||||
"",
|
"",
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 12, fontWeight: FontWeight.w400, color: Colors.black),
|
fontSize: 12,
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
SizedBox(height: 8),
|
SizedBox(height: 8),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -1296,10 +1341,8 @@ class _OfficeDetailsState extends State<OfficeDetails> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
handleReset();
|
handleReset();
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text("Reset", style: GoogleFonts.poppins(fontSize: 11)),
|
||||||
"Reset",
|
),
|
||||||
style: GoogleFonts.poppins(fontSize: 11),
|
|
||||||
))
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -313,6 +313,8 @@ class _UserListScreenState extends State<UserListScreen> {
|
|||||||
(user['role_value']?.toLowerCase().contains(lowerQuery) ??
|
(user['role_value']?.toLowerCase().contains(lowerQuery) ??
|
||||||
false);
|
false);
|
||||||
}).toList();
|
}).toList();
|
||||||
|
|
||||||
|
currentPage = 0;
|
||||||
});
|
});
|
||||||
print("filteredPlans: $filteredUsers");
|
print("filteredPlans: $filteredUsers");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,10 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/rendering.dart';
|
// import 'package:flutter/rendering.dart';
|
||||||
import 'dart:html' as html;
|
import 'dart:html' as html;
|
||||||
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
import 'package:frontend/config/apiUrl.dart'; // 1 newly added
|
||||||
|
import 'package:frontend/services/apiService.dart';
|
||||||
|
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
@ -23,13 +24,14 @@ class MyApp extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MyAppState extends State<MyApp> {
|
class _MyAppState extends State<MyApp> {
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
String? _authCode;
|
String? _authCode;
|
||||||
String? userRole;
|
String? userRole;
|
||||||
bool _isAuthRedirect = false;
|
bool _isAuthRedirect = false;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
// SemanticsBinding.instance.ensureSemantics(); // ✅ Safe here
|
||||||
if (kIsWeb) {
|
if (kIsWeb) {
|
||||||
final uri = Uri.parse(html.window.location.href);
|
final uri = Uri.parse(html.window.location.href);
|
||||||
if (uri.path == '/authredirection' &&
|
if (uri.path == '/authredirection' &&
|
||||||
@ -119,6 +121,7 @@ class _MyAppState extends State<MyApp> {
|
|||||||
print("userData11 - ${userData['role']}");
|
print("userData11 - ${userData['role']}");
|
||||||
print("userData12 - $userRole");
|
print("userData12 - $userRole");
|
||||||
}
|
}
|
||||||
|
apiService.getOrganizationData();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Error decoding token: $e');
|
print('Error decoding token: $e');
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,18 +1,13 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:frontend/config/apiUrl.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart'; // don't forget
|
import 'package:shared_preferences/shared_preferences.dart'; // don't forget
|
||||||
import '../services/apiService.dart';
|
import '../services/apiService.dart';
|
||||||
import '../utils/auth_utils.dart';
|
import '../utils/auth_utils.dart';
|
||||||
|
|
||||||
enum TabSelection {
|
enum TabSelection { dashboard, allTrips, myTrips, myApprovals, allMenu }
|
||||||
dashboard,
|
|
||||||
allTrips,
|
|
||||||
myTrips,
|
|
||||||
myApprovals,
|
|
||||||
allMenu,
|
|
||||||
}
|
|
||||||
|
|
||||||
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
|
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||||
final bool isDesktop;
|
final bool isDesktop;
|
||||||
@ -131,6 +126,64 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getOrganizationData() async {
|
Future<void> getOrganizationData() async {
|
||||||
|
try {
|
||||||
|
print("getUpdatedServices");
|
||||||
|
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? orgDataString = prefs.getString('org_data');
|
||||||
|
|
||||||
|
if (orgDataString != null) {
|
||||||
|
// final result = await apiService.fetchOrganization();
|
||||||
|
|
||||||
|
final Map<String, dynamic> result = jsonDecode(orgDataString);
|
||||||
|
print("UUPdatedServices - $result");
|
||||||
|
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
print("UUPdatedServices - $result");
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
selectedOrg = result;
|
||||||
|
|
||||||
|
layoutColor =
|
||||||
|
selectedOrg?['layout_color'] != null
|
||||||
|
? Color(int.parse(selectedOrg!['layout_color']))
|
||||||
|
: Colors.white;
|
||||||
|
|
||||||
|
bodyColor =
|
||||||
|
selectedOrg?['color'] != null
|
||||||
|
? Color(
|
||||||
|
int.parse(
|
||||||
|
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
||||||
|
radix: 16,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: Colors.blue;
|
||||||
|
|
||||||
|
String? rawLogoPath = selectedOrg?['logo'];
|
||||||
|
if (rawLogoPath != null && rawLogoPath.contains('/assets')) {
|
||||||
|
const baseUrl = apiUrl;
|
||||||
|
|
||||||
|
// const baseUrl = "https://apitest.tripapprovaltool.com";
|
||||||
|
final assetPath = rawLogoPath.split('/assets').last;
|
||||||
|
selectedOrg!['logo'] = "$baseUrl/assets$assetPath";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save to SharedPreferences
|
||||||
|
await prefs.setString('layout_color', selectedOrg?['layout_color']);
|
||||||
|
await prefs.setString('body_color', selectedOrg?['color']);
|
||||||
|
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
||||||
|
|
||||||
|
print(
|
||||||
|
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print("Error : $e");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> getOrganizationData1() async {
|
||||||
try {
|
try {
|
||||||
print("getUpdatedServices");
|
print("getUpdatedServices");
|
||||||
|
|
||||||
@ -142,14 +195,19 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
selectedOrg = result;
|
selectedOrg = result;
|
||||||
|
|
||||||
layoutColor = selectedOrg?['layout_color'] != null
|
layoutColor =
|
||||||
|
selectedOrg?['layout_color'] != null
|
||||||
? Color(int.parse(selectedOrg!['layout_color']))
|
? Color(int.parse(selectedOrg!['layout_color']))
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
|
|
||||||
bodyColor = selectedOrg?['color'] != null
|
bodyColor =
|
||||||
? Color(int.parse(
|
selectedOrg?['color'] != null
|
||||||
|
? Color(
|
||||||
|
int.parse(
|
||||||
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
||||||
radix: 16))
|
radix: 16,
|
||||||
|
),
|
||||||
|
)
|
||||||
: Colors.blue;
|
: Colors.blue;
|
||||||
|
|
||||||
String? rawLogoPath = selectedOrg?['logo'];
|
String? rawLogoPath = selectedOrg?['logo'];
|
||||||
@ -166,22 +224,32 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor");
|
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor",
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error : $e");
|
print("Error : $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// void handleTabChange(TabSelection tab, String route) {
|
||||||
|
// final currentUri =
|
||||||
|
// GoRouterState.of(context).uri.toString(); // ✅ safer than `.location`
|
||||||
|
// print("currentUri - $currentUri");
|
||||||
|
//
|
||||||
|
// if (currentUri != route) {
|
||||||
|
// setState(() {
|
||||||
|
// selectedTab = tab;
|
||||||
|
// });
|
||||||
|
// context.go(route);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
void handleTabChange(TabSelection tab, String route) {
|
void handleTabChange(TabSelection tab, String route) {
|
||||||
final currentUri =
|
final currentUri = GoRouterState.of(context).uri.toString();
|
||||||
GoRouterState.of(context).uri.toString(); // ✅ safer than `.location`
|
|
||||||
print("currentUri - $currentUri");
|
|
||||||
|
|
||||||
if (currentUri != route) {
|
if (currentUri != route) {
|
||||||
setState(() {
|
context.go(route); // 🔄 Let navigation happen
|
||||||
selectedTab = tab;
|
// The tab selection will automatically be updated by didChangeDependencies
|
||||||
});
|
|
||||||
context.go(route);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -225,18 +293,21 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
|
|
||||||
titleSpacing: 0,
|
titleSpacing: 0,
|
||||||
|
|
||||||
title: !widget.isDesktop
|
title:
|
||||||
|
!widget.isDesktop
|
||||||
? Text('')
|
? Text('')
|
||||||
: Padding(
|
: Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
horizontal: MediaQuery.of(context).size.width * 0.05,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
// padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
|
||||||
|
|
||||||
child: selectedOrg?['logo'] != null
|
// padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||||
|
child:
|
||||||
|
selectedOrg?['logo'] != null
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
height: 60,
|
height: 60,
|
||||||
child: ClipRect(
|
child: ClipRect(
|
||||||
@ -253,7 +324,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
|
)
|
||||||
: const CircleAvatar(
|
: const CircleAvatar(
|
||||||
radius: 20,
|
radius: 20,
|
||||||
// backgroundColor: Colors.white,
|
// backgroundColor: Colors.white,
|
||||||
@ -264,9 +336,7 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
SizedBox(width: MediaQuery.of(context).size.width * 0.18),
|
||||||
width: MediaQuery.of(context).size.width * 0.18,
|
|
||||||
),
|
|
||||||
Container(
|
Container(
|
||||||
width: MediaQuery.of(context).size.width * 0.35,
|
width: MediaQuery.of(context).size.width * 0.35,
|
||||||
child: Row(
|
child: Row(
|
||||||
@ -277,7 +347,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
buildNavItem(
|
buildNavItem(
|
||||||
"Dashboard",
|
"Dashboard",
|
||||||
() => handleTabChange(
|
() => handleTabChange(
|
||||||
TabSelection.dashboard, '/StatusDashboard'),
|
TabSelection.dashboard,
|
||||||
|
'/StatusDashboard',
|
||||||
|
),
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
isSelected: selectedTab == TabSelection.dashboard,
|
isSelected: selectedTab == TabSelection.dashboard,
|
||||||
icon: Icons.dashboard,
|
icon: Icons.dashboard,
|
||||||
@ -291,7 +363,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
buildNavItem(
|
buildNavItem(
|
||||||
"All Trips",
|
"All Trips",
|
||||||
() => handleTabChange(
|
() => handleTabChange(
|
||||||
TabSelection.allTrips, '/listAllPlan'),
|
TabSelection.allTrips,
|
||||||
|
'/listAllPlan',
|
||||||
|
),
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
isSelected: selectedTab == TabSelection.allTrips,
|
isSelected: selectedTab == TabSelection.allTrips,
|
||||||
icon: Icons.format_list_bulleted_rounded,
|
icon: Icons.format_list_bulleted_rounded,
|
||||||
@ -303,7 +377,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
buildNavItem(
|
buildNavItem(
|
||||||
"Trips",
|
"Trips",
|
||||||
() => handleTabChange(
|
() => handleTabChange(
|
||||||
TabSelection.myTrips, '/listTravelAgentPlan'),
|
TabSelection.myTrips,
|
||||||
|
'/listTravelAgentPlan',
|
||||||
|
),
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
// () => context.go('/listTravelAgentPlan'),
|
// () => context.go('/listTravelAgentPlan'),
|
||||||
isSelected: selectedTab == TabSelection.myTrips,
|
isSelected: selectedTab == TabSelection.myTrips,
|
||||||
@ -314,7 +390,9 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
buildNavItem(
|
buildNavItem(
|
||||||
"My Trips",
|
"My Trips",
|
||||||
() => handleTabChange(
|
() => handleTabChange(
|
||||||
TabSelection.myTrips, '/listPlan'),
|
TabSelection.myTrips,
|
||||||
|
'/listPlan',
|
||||||
|
),
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
// () => context.go('/listPlan'),
|
// () => context.go('/listPlan'),
|
||||||
isSelected: selectedTab == TabSelection.myTrips,
|
isSelected: selectedTab == TabSelection.myTrips,
|
||||||
@ -326,10 +404,13 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
"My Approvals",
|
"My Approvals",
|
||||||
|
|
||||||
() => handleTabChange(
|
() => handleTabChange(
|
||||||
TabSelection.myApprovals, '/ApprovalList'),
|
TabSelection.myApprovals,
|
||||||
|
'/ApprovalList',
|
||||||
|
),
|
||||||
layoutColor!,
|
layoutColor!,
|
||||||
// () => context.go('/ApprovalList'),
|
// () => context.go('/ApprovalList'),
|
||||||
isSelected: selectedTab == TabSelection.myApprovals,
|
isSelected:
|
||||||
|
selectedTab == TabSelection.myApprovals,
|
||||||
icon: Icons.verified_outlined,
|
icon: Icons.verified_outlined,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -342,12 +423,14 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
actions: [
|
actions: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.symmetric(
|
||||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
horizontal: MediaQuery.of(context).size.width * 0.05,
|
||||||
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
// if (userData?["role"] != "User")
|
// if (userData?["role"] != "User")
|
||||||
Builder(
|
Builder(
|
||||||
builder: (context) => PopupMenuButton<String>(
|
builder:
|
||||||
|
(context) => PopupMenuButton<String>(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
padding: EdgeInsets.zero,
|
padding: EdgeInsets.zero,
|
||||||
offset: const Offset(0, 50), // 👈 shift it 50 pixels down
|
offset: const Offset(0, 50), // 👈 shift it 50 pixels down
|
||||||
@ -394,20 +477,23 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
|||||||
|
|
||||||
// itemBuilder: (BuildContext context) =>
|
// itemBuilder: (BuildContext context) =>
|
||||||
// menuItems.map(buildMenuItem).toList(),
|
// menuItems.map(buildMenuItem).toList(),
|
||||||
|
|
||||||
itemBuilder: (BuildContext context) {
|
itemBuilder: (BuildContext context) {
|
||||||
// final isUser = userData?["role"] == "User";
|
// final isUser = userData?["role"] == "User";
|
||||||
final role = userData?["role"];
|
final role = userData?["role"];
|
||||||
List<Map<String, dynamic>> filteredItems;
|
List<Map<String, dynamic>> filteredItems;
|
||||||
|
|
||||||
if (role == "User") {
|
if (role == "User") {
|
||||||
filteredItems = menuItems
|
filteredItems =
|
||||||
.where((item) =>
|
menuItems
|
||||||
|
.where(
|
||||||
|
(item) =>
|
||||||
item['value'] == '/CreateUserDetails' ||
|
item['value'] == '/CreateUserDetails' ||
|
||||||
item['value'] == '/logout')
|
item['value'] == '/logout',
|
||||||
|
)
|
||||||
.toList();
|
.toList();
|
||||||
} else if (role == "Travel Agent") {
|
} else if (role == "Travel Agent") {
|
||||||
filteredItems = menuItems
|
filteredItems =
|
||||||
|
menuItems
|
||||||
.where((item) => item['value'] == '/logout')
|
.where((item) => item['value'] == '/logout')
|
||||||
.toList();
|
.toList();
|
||||||
} else {
|
} else {
|
||||||
@ -497,12 +583,12 @@ final List<Map<String, dynamic>> menuItems = [
|
|||||||
{
|
{
|
||||||
'value': '/OrganizationSettings',
|
'value': '/OrganizationSettings',
|
||||||
'icon': Icons.business,
|
'icon': Icons.business,
|
||||||
'label': 'Org Management'
|
'label': 'Org Management',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'value': '/listUser',
|
'value': '/listUser',
|
||||||
'icon': Icons.manage_accounts,
|
'icon': Icons.manage_accounts,
|
||||||
'label': 'User Management'
|
'label': 'User Management',
|
||||||
},
|
},
|
||||||
|
|
||||||
// {'value': '/group', 'icon': Icons.group, 'label': 'Group'},
|
// {'value': '/group', 'icon': Icons.group, 'label': 'Group'},
|
||||||
@ -518,7 +604,7 @@ final List<Map<String, dynamic>> menuItems = [
|
|||||||
{
|
{
|
||||||
'value': '/CreateUserDetails',
|
'value': '/CreateUserDetails',
|
||||||
'icon': Icons.account_circle,
|
'icon': Icons.account_circle,
|
||||||
'label': 'My Profile'
|
'label': 'My Profile',
|
||||||
},
|
},
|
||||||
{'value': '/logout', 'icon': Icons.login_outlined, 'label': 'Logout'},
|
{'value': '/logout', 'icon': Icons.login_outlined, 'label': 'Logout'},
|
||||||
];
|
];
|
||||||
@ -527,12 +613,16 @@ PopupMenuItem<String> buildMenuItem(Map<String, dynamic> item) {
|
|||||||
return PopupMenuItem<String>(
|
return PopupMenuItem<String>(
|
||||||
height: 40, // 👈 reduce PopupMenuItem height
|
height: 40, // 👈 reduce PopupMenuItem height
|
||||||
value: item['value'],
|
value: item['value'],
|
||||||
padding:
|
padding: EdgeInsets.symmetric(
|
||||||
EdgeInsets.symmetric(horizontal: 12), // 👈 control left-right spacing
|
horizontal: 12,
|
||||||
|
), // 👈 control left-right spacing
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(item['icon'],
|
Icon(
|
||||||
size: 18, color: Colors.black87), // 👈 smaller, cleaner icon
|
item['icon'],
|
||||||
|
size: 18,
|
||||||
|
color: Colors.black87,
|
||||||
|
), // 👈 smaller, cleaner icon
|
||||||
SizedBox(width: 10), // 👈 small space between icon and text
|
SizedBox(width: 10), // 👈 small space between icon and text
|
||||||
Text(
|
Text(
|
||||||
item['label'],
|
item['label'],
|
||||||
@ -547,8 +637,13 @@ PopupMenuItem<String> buildMenuItem(Map<String, dynamic> item) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildNavItem(String label, VoidCallback onTap, Color? layoutColor,
|
Widget buildNavItem(
|
||||||
{bool isSelected = true, IconData? icon}) {
|
String label,
|
||||||
|
VoidCallback onTap,
|
||||||
|
Color? layoutColor, {
|
||||||
|
bool isSelected = true,
|
||||||
|
IconData? icon,
|
||||||
|
}) {
|
||||||
final effectiveColor =
|
final effectiveColor =
|
||||||
isSelected ? (layoutColor ?? Colors.blue) : Colors.black;
|
isSelected ? (layoutColor ?? Colors.blue) : Colors.black;
|
||||||
|
|
||||||
@ -587,7 +682,8 @@ Widget buildNavItem(String label, VoidCallback onTap, Color? layoutColor,
|
|||||||
duration: const Duration(milliseconds: 300),
|
duration: const Duration(milliseconds: 300),
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
height: 2,
|
height: 2,
|
||||||
width: isSelected
|
width:
|
||||||
|
isSelected
|
||||||
? 50
|
? 50
|
||||||
: 0, // Animate width (make sure isSelected changes)
|
: 0, // Animate width (make sure isSelected changes)
|
||||||
color: effectiveColor,
|
color: effectiveColor,
|
||||||
|
|||||||
@ -84,7 +84,14 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
try {
|
try {
|
||||||
print("getUpdatedServices");
|
print("getUpdatedServices");
|
||||||
|
|
||||||
final result = await apiService.fetchOrganization();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final String? orgDataString = prefs.getString('org_data');
|
||||||
|
|
||||||
|
if (orgDataString != null) {
|
||||||
|
// final result = await apiService.fetchOrganization();
|
||||||
|
|
||||||
|
final Map<String, dynamic> result = jsonDecode(orgDataString);
|
||||||
|
print("UUPdatedServices - $result");
|
||||||
|
|
||||||
final prefs = await SharedPreferences.getInstance();
|
final prefs = await SharedPreferences.getInstance();
|
||||||
print("UUPdatedServices - $result");
|
print("UUPdatedServices - $result");
|
||||||
@ -92,14 +99,19 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
selectedOrg = result;
|
selectedOrg = result;
|
||||||
|
|
||||||
layoutColor = selectedOrg?['layout_color'] != null
|
layoutColor =
|
||||||
|
selectedOrg?['layout_color'] != null
|
||||||
? Color(int.parse(selectedOrg!['layout_color']))
|
? Color(int.parse(selectedOrg!['layout_color']))
|
||||||
: Colors.white;
|
: Colors.white;
|
||||||
|
|
||||||
bodyColor = selectedOrg?['color'] != null
|
bodyColor =
|
||||||
? Color(int.parse(
|
selectedOrg?['color'] != null
|
||||||
|
? Color(
|
||||||
|
int.parse(
|
||||||
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
selectedOrg!['color'].toString().replaceFirst('0x', ''),
|
||||||
radix: 16))
|
radix: 16,
|
||||||
|
),
|
||||||
|
)
|
||||||
: Colors.blue;
|
: Colors.blue;
|
||||||
|
|
||||||
String? rawLogoPath = selectedOrg?['logo'];
|
String? rawLogoPath = selectedOrg?['logo'];
|
||||||
@ -116,7 +128,9 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
await prefs.setString('body_color', selectedOrg?['plan_action']);
|
||||||
|
|
||||||
print(
|
print(
|
||||||
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor");
|
"Layout Color- ${selectedOrg?['layout_color']} - $layoutColor ---------- bodyColor - $bodyColor",
|
||||||
|
);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error : $e");
|
print("Error : $e");
|
||||||
}
|
}
|
||||||
@ -126,7 +140,6 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget drawerContent = Container(
|
Widget drawerContent = Container(
|
||||||
// color: Colors.white,
|
// color: Colors.white,
|
||||||
|
|
||||||
child: Container(
|
child: Container(
|
||||||
margin: const EdgeInsets.all(18),
|
margin: const EdgeInsets.all(18),
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -169,29 +182,49 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
// _buildDrawerItem(context, Icons.home_outlined, 'Home', '/home'),
|
// _buildDrawerItem(context, Icons.home_outlined, 'Home', '/home'),
|
||||||
|
if (userData?["role"] == "Org Admin" ||
|
||||||
|
userData?["role"] == "Travel Admin")
|
||||||
|
_buildDrawerItem(
|
||||||
|
context,
|
||||||
|
Icons.dashboard,
|
||||||
|
'Dashboard',
|
||||||
|
'/StatusDashboard',
|
||||||
|
),
|
||||||
|
|
||||||
if (userData?["role"] == "Org Admin" ||
|
if (userData?["role"] == "Org Admin" ||
|
||||||
userData?["role"] == "Travel Admin")
|
userData?["role"] == "Travel Admin")
|
||||||
_buildDrawerItem(context, Icons.dashboard, 'Dashboard',
|
_buildDrawerItem(
|
||||||
'/StatusDashboard'),
|
context,
|
||||||
|
Icons.insights_outlined,
|
||||||
if (userData?["role"] == "Org Admin" ||
|
'All Trips',
|
||||||
userData?["role"] == "Travel Admin")
|
'/listAllPlan',
|
||||||
_buildDrawerItem(context, Icons.insights_outlined, 'All Trips',
|
),
|
||||||
'/listAllPlan'),
|
|
||||||
|
|
||||||
if (userDetails["role"] == "Travel Agent")
|
if (userDetails["role"] == "Travel Agent")
|
||||||
_buildDrawerItem(context, Icons.assessment_outlined,
|
_buildDrawerItem(
|
||||||
'My Approvals', '/listTravelAgentPlan'),
|
context,
|
||||||
|
Icons.assessment_outlined,
|
||||||
|
'My Approvals',
|
||||||
|
'/listTravelAgentPlan',
|
||||||
|
),
|
||||||
|
|
||||||
if (userDetails["role"] != "Travel Agent")
|
if (userDetails["role"] != "Travel Agent")
|
||||||
_buildDrawerItem(context, Icons.request_page_outlined, 'My Trips',
|
_buildDrawerItem(
|
||||||
'/listPlan'),
|
context,
|
||||||
|
Icons.request_page_outlined,
|
||||||
|
'My Trips',
|
||||||
|
'/listPlan',
|
||||||
|
),
|
||||||
|
|
||||||
if (userDetails["role"] != "Travel Agent")
|
if (userDetails["role"] != "Travel Agent")
|
||||||
_buildDrawerItem(context, Icons.assessment_outlined,
|
_buildDrawerItem(
|
||||||
'My Approvals', '/ApprovalList'),
|
context,
|
||||||
|
Icons.assessment_outlined,
|
||||||
|
'My Approvals',
|
||||||
|
'/ApprovalList',
|
||||||
|
),
|
||||||
|
|
||||||
SizedBox(height: MediaQuery.of(context).size.height * 0.5),
|
SizedBox(height: MediaQuery.of(context).size.height * 0.5),
|
||||||
Container(
|
Container(
|
||||||
@ -206,8 +239,10 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
"Powered by",
|
"Powered by",
|
||||||
style:
|
style: TextStyle(
|
||||||
TextStyle(fontSize: 11, color: Color(0xFF212121)),
|
fontSize: 11,
|
||||||
|
color: Color(0xFF212121),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Image.asset(
|
Image.asset(
|
||||||
'assets/images/login/logoNew.jpg',
|
'assets/images/login/logoNew.jpg',
|
||||||
@ -226,7 +261,8 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return Drawer(
|
return Drawer(
|
||||||
child: ListView(padding: EdgeInsets.zero, children: [drawerContent]));
|
child: ListView(padding: EdgeInsets.zero, children: [drawerContent]),
|
||||||
|
);
|
||||||
|
|
||||||
// if (widget.isDesktop) {
|
// if (widget.isDesktop) {
|
||||||
// // Sidebar for Desktop (always visible)**
|
// // Sidebar for Desktop (always visible)**
|
||||||
@ -244,7 +280,11 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
|
|
||||||
/// **Reusable Drawer Item**
|
/// **Reusable Drawer Item**
|
||||||
Widget _buildDrawerItem(
|
Widget _buildDrawerItem(
|
||||||
BuildContext context, IconData icon, String title, String route) {
|
BuildContext context,
|
||||||
|
IconData icon,
|
||||||
|
String title,
|
||||||
|
String route,
|
||||||
|
) {
|
||||||
String selectedRoute = GoRouterState.of(context).uri.toString();
|
String selectedRoute = GoRouterState.of(context).uri.toString();
|
||||||
|
|
||||||
// return Container(
|
// return Container(
|
||||||
@ -287,10 +327,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
return Material(
|
return Material(
|
||||||
color: selectedRoute == route ? bodyColor : Colors.transparent,
|
color: selectedRoute == route ? bodyColor : Colors.transparent,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(
|
leading: Icon(icon, size: 20),
|
||||||
icon,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
|
|
||||||
@ -305,8 +342,8 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
// color: Color(0xFF475569),
|
// color: Color(0xFF475569),
|
||||||
// fontFamily: "Archivo"),
|
// fontFamily: "Archivo"),
|
||||||
),
|
),
|
||||||
// tileColor: selectedRoute == route ? Colors.blue.shade50 : null,
|
|
||||||
|
|
||||||
|
// tileColor: selectedRoute == route ? Colors.blue.shade50 : null,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (route == '/') {
|
if (route == '/') {
|
||||||
// Handle logout separately
|
// Handle logout separately
|
||||||
@ -316,7 +353,8 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
} else {
|
} else {
|
||||||
context.go(route);
|
context.go(route);
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,11 +376,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
child: ExpansionTile(
|
child: ExpansionTile(
|
||||||
tilePadding: EdgeInsets.symmetric(horizontal: 16),
|
tilePadding: EdgeInsets.symmetric(horizontal: 16),
|
||||||
// childrenPadding: EdgeInsets.only(left: 36),
|
// childrenPadding: EdgeInsets.only(left: 36),
|
||||||
leading: Icon(
|
leading: Icon(icon, size: 20, color: Color(0xFF475569)),
|
||||||
icon,
|
|
||||||
size: 20,
|
|
||||||
color: Color(0xFF475569),
|
|
||||||
),
|
|
||||||
title: Row(
|
title: Row(
|
||||||
children: [
|
children: [
|
||||||
// You could manually build this instead of using `leading`, but it's simpler here
|
// You could manually build this instead of using `leading`, but it's simpler here
|
||||||
@ -378,11 +412,7 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 44.0, vertical: 8.0),
|
padding: const EdgeInsets.symmetric(horizontal: 44.0, vertical: 8.0),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(Icons.circle_rounded, color: Color(0xFF475569), size: 6),
|
||||||
Icons.circle_rounded,
|
|
||||||
color: Color(0xFF475569),
|
|
||||||
size: 6,
|
|
||||||
),
|
|
||||||
SizedBox(width: 8),
|
SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
title,
|
title,
|
||||||
@ -399,20 +429,22 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildExpandableItem1(BuildContext context, IconData icon,
|
Widget _buildExpandableItem1(
|
||||||
String title, List<Widget> children) {
|
BuildContext context,
|
||||||
|
IconData icon,
|
||||||
|
String title,
|
||||||
|
List<Widget> children,
|
||||||
|
) {
|
||||||
return ExpansionTile(
|
return ExpansionTile(
|
||||||
leading: Icon(
|
leading: Icon(icon, size: 20),
|
||||||
icon,
|
|
||||||
size: 20,
|
|
||||||
),
|
|
||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
color: Color(0xFF475569),
|
color: Color(0xFF475569),
|
||||||
fontFamily: "Archivo"),
|
fontFamily: "Archivo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
collapsedBackgroundColor: Colors.transparent,
|
collapsedBackgroundColor: Colors.transparent,
|
||||||
shape: const Border(), // Removes top and bottom dividers
|
shape: const Border(), // Removes top and bottom dividers
|
||||||
@ -423,20 +455,20 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSubDrawerItem1(
|
Widget _buildSubDrawerItem1(
|
||||||
BuildContext context, String title, String route) {
|
BuildContext context,
|
||||||
|
String title,
|
||||||
|
String route,
|
||||||
|
) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: Icon(
|
leading: Icon(Icons.circle_rounded, color: Color(0xFF475569), size: 8),
|
||||||
Icons.circle_rounded,
|
|
||||||
color: Color(0xFF475569),
|
|
||||||
size: 8,
|
|
||||||
),
|
|
||||||
title: Text(
|
title: Text(
|
||||||
title,
|
title,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
color: Color(0xFF475569),
|
color: Color(0xFF475569),
|
||||||
fontFamily: "Archivo"),
|
fontFamily: "Archivo",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.go(route);
|
context.go(route);
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import 'package:frontend/Screens/userManagement/create_user/create_user1.dart';
|
|||||||
import 'package:frontend/Screens/userManagement/user_List.dart';
|
import 'package:frontend/Screens/userManagement/user_List.dart';
|
||||||
import 'package:frontend/routes/organizationSetting.dart';
|
import 'package:frontend/routes/organizationSetting.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
import '../Screens/allTrips/list_all_plans.dart';
|
import '../Screens/allTrips/list_all_plans.dart';
|
||||||
import '../Screens/allTrips/travel_agent_list.dart';
|
import '../Screens/allTrips/travel_agent_list.dart';
|
||||||
@ -23,6 +24,7 @@ import '../Screens/approvals/approval_list.dart';
|
|||||||
import '../Screens/group/group.dart';
|
import '../Screens/group/group.dart';
|
||||||
import '../Screens/group/groupList.dart';
|
import '../Screens/group/groupList.dart';
|
||||||
import '../Screens/myTemplates/template.dart';
|
import '../Screens/myTemplates/template.dart';
|
||||||
|
import '../Screens/myTemplates/templateForex.dart';
|
||||||
import '../Screens/myTemplates/templateTest.dart';
|
import '../Screens/myTemplates/templateTest.dart';
|
||||||
import '../Screens/userManagement/create_user/create_user.dart';
|
import '../Screens/userManagement/create_user/create_user.dart';
|
||||||
import '../Screens/department/department_list.dart';
|
import '../Screens/department/department_list.dart';
|
||||||
@ -30,52 +32,57 @@ import '../Screens/costCenter/costCenter_list.dart';
|
|||||||
import '../Screens/dashboard/status_dashboard.dart';
|
import '../Screens/dashboard/status_dashboard.dart';
|
||||||
import '../Screens/hotels/hotels_list.dart';
|
import '../Screens/hotels/hotels_list.dart';
|
||||||
import '../Screens/traveller/travellerList.dart';
|
import '../Screens/traveller/travellerList.dart';
|
||||||
|
import 'mainLayout.dart';
|
||||||
|
|
||||||
final GoRouter router = GoRouter(
|
final GoRouter router = GoRouter(
|
||||||
routes: [
|
routes: [
|
||||||
|
// Public routes without app bar
|
||||||
GoRoute(path: '/', builder: (context, state) => LoginPage()),
|
GoRoute(path: '/', builder: (context, state) => LoginPage()),
|
||||||
// GoRoute(
|
|
||||||
// path: '/authredirection',
|
// Routes that share the app bar and layout (nested routes)
|
||||||
// builder: (context, state) {
|
ShellRoute(
|
||||||
// final code = state.uri.queryParameters['code'];
|
builder: (context, state, child) {
|
||||||
// return MicrosoftPage(code: code);
|
// Use ResponsiveBuilder here to detect isDesktop and pass to MainLayout
|
||||||
|
return child;
|
||||||
|
// return ResponsiveBuilder(
|
||||||
|
// builder: (context, sizingInfo) {
|
||||||
|
// bool isDesktop =
|
||||||
|
// sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||||
|
//
|
||||||
|
// return MainLayout(isDesktop: isDesktop, child: child);
|
||||||
// },
|
// },
|
||||||
// ),
|
// );
|
||||||
|
},
|
||||||
|
routes: [
|
||||||
GoRoute(path: '/home', builder: (context, state) => HomePage()),
|
GoRoute(path: '/home', builder: (context, state) => HomePage()),
|
||||||
GoRoute(path: '/listAllPlan', builder: (context, state) => ListAllPlans()),
|
GoRoute(
|
||||||
|
path: '/listAllPlan',
|
||||||
|
builder: (context, state) => ListAllPlans(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/listTravelAgentPlan',
|
path: '/listTravelAgentPlan',
|
||||||
builder: (context, state) => TravelAgentListPlans(),
|
builder: (context, state) => TravelAgentListPlans(),
|
||||||
),
|
),
|
||||||
GoRoute(path: '/listPlan', builder: (context, state) => ListPlans()),
|
GoRoute(path: '/listPlan', builder: (context, state) => ListPlans()),
|
||||||
GoRoute(path: '/createPlan', builder: (context, state) => CreatePlan()),
|
GoRoute(path: '/createPlan', builder: (context, state) => CreatePlan()),
|
||||||
GoRoute(path: '/allTrips/trips', builder: (context, state) => CreatePlan()),
|
GoRoute(
|
||||||
GoRoute(path: '/approver/plans', builder: (context, state) => CreatePlan()),
|
path: '/allTrips/trips',
|
||||||
GoRoute(path: '/listUser', builder: (context, state) => UserListScreen()),
|
builder: (context, state) => CreatePlan(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/approver/plans',
|
||||||
|
builder: (context, state) => CreatePlan(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/listUser',
|
||||||
|
builder: (context, state) => UserListScreen(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/CreateUserDetails',
|
path: '/CreateUserDetails',
|
||||||
builder: (context, state) => CreateUserFormDetials(),
|
builder: (context, state) => CreateUserFormDetials(),
|
||||||
// builder: (context, state) {
|
|
||||||
// final userParam = state.uri.queryParameters['user'];
|
|
||||||
//
|
|
||||||
// final isEditProfile =
|
|
||||||
// state.uri.queryParameters['isEditProfile'] == 'true';
|
|
||||||
// final isViewMode = state.uri.queryParameters['isViewMode'] == 'true';
|
|
||||||
//
|
|
||||||
// final user = userParam != null
|
|
||||||
// ? jsonDecode(Uri.decodeComponent(userParam))
|
|
||||||
// : null;
|
|
||||||
//
|
|
||||||
// return CreateUserForm(
|
|
||||||
// apiselectedUser: user,
|
|
||||||
// isEditProfile: isEditProfile,
|
|
||||||
// isViewMode: isViewMode,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
),
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/Policy',
|
path: '/Policy',
|
||||||
// builder: (context, state) => Policy(),
|
|
||||||
pageBuilder:
|
pageBuilder:
|
||||||
(context, state) => MaterialPage(child: Policy.fromState(state)),
|
(context, state) => MaterialPage(child: Policy.fromState(state)),
|
||||||
),
|
),
|
||||||
@ -89,24 +96,38 @@ final GoRouter router = GoRouter(
|
|||||||
builder: (context, state) => OrganizationSetting(),
|
builder: (context, state) => OrganizationSetting(),
|
||||||
),
|
),
|
||||||
GoRoute(path: '/group', builder: (context, state) => GroupList()),
|
GoRoute(path: '/group', builder: (context, state) => GroupList()),
|
||||||
GoRoute(path: '/getPerdiem', builder: (context, state) => ForexDataList()),
|
GoRoute(
|
||||||
|
path: '/getPerdiem',
|
||||||
|
builder: (context, state) => ForexDataList(),
|
||||||
|
),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/templateList',
|
path: '/templateList',
|
||||||
builder: (context, state) => TemplatesList(),
|
builder: (context, state) => TemplatesList(),
|
||||||
),
|
),
|
||||||
// GoRoute(
|
|
||||||
// path: '/template',
|
|
||||||
// builder: (context, state) => MyHomePage(),
|
|
||||||
// ),
|
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/template',
|
path: '/template',
|
||||||
// builder: (context, state) => Template(),
|
|
||||||
pageBuilder:
|
pageBuilder:
|
||||||
(context, state) => MaterialPage(child: Template.fromState(state)),
|
(context, state) =>
|
||||||
|
MaterialPage(child: Template.fromState(state)),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/templateForex',
|
||||||
|
pageBuilder:
|
||||||
|
(context, state) =>
|
||||||
|
MaterialPage(child: TemplateForex.fromState(state)),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/approvallist',
|
||||||
|
builder: (context, state) => ApprovalList(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/department',
|
||||||
|
builder: (context, state) => DepartmentList(),
|
||||||
|
),
|
||||||
|
GoRoute(
|
||||||
|
path: '/costcenter',
|
||||||
|
builder: (context, state) => CostCenterList(),
|
||||||
),
|
),
|
||||||
GoRoute(path: '/approvallist', builder: (context, state) => ApprovalList()),
|
|
||||||
GoRoute(path: '/department', builder: (context, state) => DepartmentList()),
|
|
||||||
GoRoute(path: '/costcenter', builder: (context, state) => CostCenterList()),
|
|
||||||
GoRoute(path: '/hotels', builder: (context, state) => HotelsDataList()),
|
GoRoute(path: '/hotels', builder: (context, state) => HotelsDataList()),
|
||||||
GoRoute(
|
GoRoute(
|
||||||
path: '/statusdashboard',
|
path: '/statusdashboard',
|
||||||
@ -122,4 +143,102 @@ final GoRouter router = GoRouter(
|
|||||||
(context, state) => MaterialPage(child: Group.fromState(state)),
|
(context, state) => MaterialPage(child: Group.fromState(state)),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// final GoRouter router = GoRouter(
|
||||||
|
// routes: [
|
||||||
|
// GoRoute(path: '/', builder: (context, state) => LoginPage()),
|
||||||
|
// // GoRoute(
|
||||||
|
// // path: '/authredirection',
|
||||||
|
// // builder: (context, state) {
|
||||||
|
// // final code = state.uri.queryParameters['code'];
|
||||||
|
// // return MicrosoftPage(code: code);
|
||||||
|
// // },
|
||||||
|
// // ),
|
||||||
|
// GoRoute(path: '/home', builder: (context, state) => HomePage()),
|
||||||
|
// GoRoute(path: '/listAllPlan', builder: (context, state) => ListAllPlans()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/listTravelAgentPlan',
|
||||||
|
// builder: (context, state) => TravelAgentListPlans(),
|
||||||
|
// ),
|
||||||
|
// GoRoute(path: '/listPlan', builder: (context, state) => ListPlans()),
|
||||||
|
// GoRoute(path: '/createPlan', builder: (context, state) => CreatePlan()),
|
||||||
|
// GoRoute(path: '/allTrips/trips', builder: (context, state) => CreatePlan()),
|
||||||
|
// GoRoute(path: '/approver/plans', builder: (context, state) => CreatePlan()),
|
||||||
|
// GoRoute(path: '/listUser', builder: (context, state) => UserListScreen()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/CreateUserDetails',
|
||||||
|
// builder: (context, state) => CreateUserFormDetials(),
|
||||||
|
// // builder: (context, state) {
|
||||||
|
// // final userParam = state.uri.queryParameters['user'];
|
||||||
|
// //
|
||||||
|
// // final isEditProfile =
|
||||||
|
// // state.uri.queryParameters['isEditProfile'] == 'true';
|
||||||
|
// // final isViewMode = state.uri.queryParameters['isViewMode'] == 'true';
|
||||||
|
// //
|
||||||
|
// // final user = userParam != null
|
||||||
|
// // ? jsonDecode(Uri.decodeComponent(userParam))
|
||||||
|
// // : null;
|
||||||
|
// //
|
||||||
|
// // return CreateUserForm(
|
||||||
|
// // apiselectedUser: user,
|
||||||
|
// // isEditProfile: isEditProfile,
|
||||||
|
// // isViewMode: isViewMode,
|
||||||
|
// // );
|
||||||
|
// // }
|
||||||
|
// ),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/Policy',
|
||||||
|
// // builder: (context, state) => Policy(),
|
||||||
|
// pageBuilder:
|
||||||
|
// (context, state) => MaterialPage(child: Policy.fromState(state)),
|
||||||
|
// ),
|
||||||
|
// GoRoute(path: '/PolicyList', builder: (context, state) => PolicyList()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/OrganizationSetup',
|
||||||
|
// builder: (context, state) => OrgSetUp(),
|
||||||
|
// ),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/OrganizationSettings',
|
||||||
|
// builder: (context, state) => OrganizationSetting(),
|
||||||
|
// ),
|
||||||
|
// GoRoute(path: '/group', builder: (context, state) => GroupList()),
|
||||||
|
// GoRoute(path: '/getPerdiem', builder: (context, state) => ForexDataList()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/templateList',
|
||||||
|
// builder: (context, state) => TemplatesList(),
|
||||||
|
// ),
|
||||||
|
// // GoRoute(
|
||||||
|
// // path: '/template',
|
||||||
|
// // builder: (context, state) => MyHomePage(),
|
||||||
|
// // ),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/template',
|
||||||
|
// // builder: (context, state) => Template(),
|
||||||
|
// pageBuilder:
|
||||||
|
// (context, state) => MaterialPage(child: Template.fromState(state)),
|
||||||
|
// ),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/templateForex',
|
||||||
|
// pageBuilder:
|
||||||
|
// (context, state) =>
|
||||||
|
// MaterialPage(child: TemplateForex.fromState(state)),
|
||||||
|
// ),
|
||||||
|
// GoRoute(path: '/approvallist', builder: (context, state) => ApprovalList()),
|
||||||
|
// GoRoute(path: '/department', builder: (context, state) => DepartmentList()),
|
||||||
|
// GoRoute(path: '/costcenter', builder: (context, state) => CostCenterList()),
|
||||||
|
// GoRoute(path: '/hotels', builder: (context, state) => HotelsDataList()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/statusdashboard',
|
||||||
|
// builder: (context, state) => StatusDashboard(),
|
||||||
|
// ),
|
||||||
|
// GoRoute(path: '/traveller', builder: (context, state) => TravellerList()),
|
||||||
|
// GoRoute(
|
||||||
|
// path: '/CreateGroup',
|
||||||
|
// pageBuilder:
|
||||||
|
// (context, state) => MaterialPage(child: Group.fromState(state)),
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// );
|
||||||
|
|||||||
33
lib/routes/mainLayout.dart
Normal file
33
lib/routes/mainLayout.dart
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import 'custom_appBar.dart';
|
||||||
|
import 'custom_drawer.dart';
|
||||||
|
|
||||||
|
class MainLayout extends StatelessWidget {
|
||||||
|
final Widget child;
|
||||||
|
final bool isDesktop;
|
||||||
|
|
||||||
|
const MainLayout({required this.child, required this.isDesktop, Key? key})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
backgroundColor: const Color(0xFFf5f5f5),
|
||||||
|
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||||
|
drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||||
|
body: Padding(
|
||||||
|
padding:
|
||||||
|
isDesktop
|
||||||
|
? EdgeInsets.symmetric(
|
||||||
|
horizontal: MediaQuery.of(context).size.width * 0.1,
|
||||||
|
vertical: 0,
|
||||||
|
)
|
||||||
|
: EdgeInsets.zero,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
|
|||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
|
import '../services/apiService.dart';
|
||||||
import 'custom_appBar.dart';
|
import 'custom_appBar.dart';
|
||||||
import 'custom_drawer.dart';
|
import 'custom_drawer.dart';
|
||||||
|
|
||||||
@ -15,6 +16,8 @@ class OrganizationSetting extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class OrganizationSettingState extends State<OrganizationSetting> {
|
class OrganizationSettingState extends State<OrganizationSetting> {
|
||||||
|
final ApiService apiService = ApiService();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ResponsiveBuilder(
|
return ResponsiveBuilder(
|
||||||
@ -84,7 +87,7 @@ class OrganizationSettingState extends State<OrganizationSetting> {
|
|||||||
'description': 'Create and Edit Perdiem Amount',
|
'description': 'Create and Edit Perdiem Amount',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'value': '/department',
|
'value': '/forexTexmplate',
|
||||||
'icon': Icons.group_add_outlined,
|
'icon': Icons.group_add_outlined,
|
||||||
'label': 'Forex Template',
|
'label': 'Forex Template',
|
||||||
'description': 'Create and Edit Template',
|
'description': 'Create and Edit Template',
|
||||||
@ -244,9 +247,21 @@ class OrganizationSettingState extends State<OrganizationSetting> {
|
|||||||
child: Card(
|
child: Card(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
|
if (item['value'] as String ==
|
||||||
|
"/forexTexmplate") {
|
||||||
|
final data =
|
||||||
|
await apiService.getForexTemplate();
|
||||||
|
print("ForexId -- $data");
|
||||||
|
|
||||||
|
context.go(
|
||||||
|
'/templateForex',
|
||||||
|
extra: {'templateData': data},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
final route = item['value'] as String;
|
final route = item['value'] as String;
|
||||||
context.go(route);
|
context.go(route);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.all(12),
|
padding: EdgeInsets.all(12),
|
||||||
|
|||||||
@ -5,11 +5,32 @@ import 'package:frontend/utils/auth_utils.dart';
|
|||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:google_fonts/google_fonts.dart';
|
import 'package:google_fonts/google_fonts.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:universal_html/html.dart' as html;
|
import 'package:universal_html/html.dart' as html;
|
||||||
import 'package:universal_html/js.dart';
|
import 'package:universal_html/js.dart';
|
||||||
import '../../config/apiUrl.dart';
|
import '../../config/apiUrl.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
class ApiService {
|
class ApiService {
|
||||||
|
Future<void> getOrganizationData() async {
|
||||||
|
try {
|
||||||
|
print("getUpdatedServices");
|
||||||
|
final result = await fetchOrganization();
|
||||||
|
print("UUPdatedServices - $result");
|
||||||
|
|
||||||
|
// ✅ Save to local storage
|
||||||
|
final prefs = await SharedPreferences.getInstance();
|
||||||
|
final jsonString = jsonEncode(result);
|
||||||
|
await prefs.setString('org_data', jsonString);
|
||||||
|
print("✅ Organization data saved to SharedPreferences.");
|
||||||
|
|
||||||
|
print("selectedOrg - $result");
|
||||||
|
} catch (e) {
|
||||||
|
print('Error fetching updatedServices list: $e');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<List<dynamic>> fetchCountryList() async {
|
Future<List<dynamic>> fetchCountryList() async {
|
||||||
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
final String apiUrldata = '$apiUrl/api/getcountryMaster';
|
||||||
final token = await getToken();
|
final token = await getToken();
|
||||||
@ -33,7 +54,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data['data'];
|
return data['data'];
|
||||||
@ -68,7 +90,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data['data'];
|
return data['data'];
|
||||||
@ -136,7 +159,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||||
@ -190,7 +214,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
List<dynamic> plansJson = data['data']; // 'data' is a Map, not a List
|
||||||
@ -239,7 +264,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> plansJson =
|
Map<String, dynamic> plansJson =
|
||||||
@ -277,7 +303,8 @@ class ApiService {
|
|||||||
print(data);
|
print(data);
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return data['data'];
|
return data['data'];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -313,7 +340,8 @@ class ApiService {
|
|||||||
print(data);
|
print(data);
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return data['data'];
|
return data['data'];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -349,7 +377,8 @@ class ApiService {
|
|||||||
print(data);
|
print(data);
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return data['data'];
|
return data['data'];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -385,7 +414,8 @@ class ApiService {
|
|||||||
print(data);
|
print(data);
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return data['data'];
|
return data['data'];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -419,7 +449,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> plansJson =
|
Map<String, dynamic> plansJson =
|
||||||
@ -460,7 +491,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure each item is a Map<String, dynamic>
|
// Make sure each item is a Map<String, dynamic>
|
||||||
@ -527,33 +559,47 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> viewPlan(BuildContext context, String planId,
|
static Future<void> viewPlan(
|
||||||
{bool isViewMode = false, bool isMyTrips = false}) async {
|
BuildContext context,
|
||||||
|
String planId, {
|
||||||
|
bool isViewMode = false,
|
||||||
|
bool isMyTrips = false,
|
||||||
|
}) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> planData = await getViewPlanEdit(planId);
|
Map<String, dynamic> planData = await getViewPlanEdit(planId);
|
||||||
print("ViewAAA - $planData");
|
print("ViewAAA - $planData");
|
||||||
|
|
||||||
context.go(isMyTrips ? '/createPlan' : '/allTrips/trips',
|
context.go(
|
||||||
extra: {'planData': planData, 'isViewMode': isViewMode});
|
isMyTrips ? '/createPlan' : '/allTrips/trips',
|
||||||
|
extra: {'planData': planData, 'isViewMode': isViewMode},
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error fetching plan: $e");
|
print("Error fetching plan: $e");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future<void> viewPlanForApprover(BuildContext context, String planId,
|
static Future<void> viewPlanForApprover(
|
||||||
String? approverId, String? delegaterId,
|
BuildContext context,
|
||||||
{bool isViewMode = false, bool isApprover = true}) async {
|
String planId,
|
||||||
|
String? approverId,
|
||||||
|
String? delegaterId, {
|
||||||
|
bool isViewMode = false,
|
||||||
|
bool isApprover = true,
|
||||||
|
}) async {
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> planData = await getViewPlanEdit(planId);
|
Map<String, dynamic> planData = await getViewPlanEdit(planId);
|
||||||
print("ViewAAA - $planData");
|
print("ViewAAA - $planData");
|
||||||
|
|
||||||
context.replace('/approver/plans', extra: {
|
context.replace(
|
||||||
|
'/approver/plans',
|
||||||
|
extra: {
|
||||||
'planData': planData,
|
'planData': planData,
|
||||||
'approverId': approverId,
|
'approverId': approverId,
|
||||||
'delegaterId': delegaterId,
|
'delegaterId': delegaterId,
|
||||||
'isViewMode': isViewMode,
|
'isViewMode': isViewMode,
|
||||||
'isApprover': isApprover,
|
'isApprover': isApprover,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print("Error fetching plan: $e");
|
print("Error fetching plan: $e");
|
||||||
}
|
}
|
||||||
@ -589,7 +635,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure each item is a Map<String, dynamic>
|
// Make sure each item is a Map<String, dynamic>
|
||||||
@ -635,7 +682,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data['data'];
|
return data['data'];
|
||||||
@ -671,7 +719,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data['data'];
|
return data['data'];
|
||||||
@ -709,11 +758,12 @@ class ApiService {
|
|||||||
// Create a blob from the response body
|
// Create a blob from the response body
|
||||||
final blob = html.Blob([response.bodyBytes]);
|
final blob = html.Blob([response.bodyBytes]);
|
||||||
|
|
||||||
// Generate a download URL for the blob
|
// Generate a download URL for the blob
|
||||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||||
|
|
||||||
// Create a link element to trigger the download
|
// Create a link element to trigger the download
|
||||||
final anchor = html.AnchorElement(href: url)
|
final anchor =
|
||||||
|
html.AnchorElement(href: url)
|
||||||
..setAttribute('download', 'trip_plan_$planId.pdf')
|
..setAttribute('download', 'trip_plan_$planId.pdf')
|
||||||
..click();
|
..click();
|
||||||
|
|
||||||
@ -772,11 +822,12 @@ class ApiService {
|
|||||||
// Create a blob from the response body
|
// Create a blob from the response body
|
||||||
final blob = html.Blob([response.bodyBytes]);
|
final blob = html.Blob([response.bodyBytes]);
|
||||||
|
|
||||||
// Generate a download URL for the blob
|
// Generate a download URL for the blob
|
||||||
final url = html.Url.createObjectUrlFromBlob(blob);
|
final url = html.Url.createObjectUrlFromBlob(blob);
|
||||||
|
|
||||||
// Create a link element to trigger the download
|
// Create a link element to trigger the download
|
||||||
final anchor = html.AnchorElement(href: url)
|
final anchor =
|
||||||
|
html.AnchorElement(href: url)
|
||||||
..setAttribute('download', 'Forex_$forexId.pdf')
|
..setAttribute('download', 'Forex_$forexId.pdf')
|
||||||
..click();
|
..click();
|
||||||
|
|
||||||
@ -835,7 +886,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
print('Single USer 1');
|
print('Single USer 1');
|
||||||
|
|
||||||
@ -880,7 +932,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<dynamic> forexList = data['data'];
|
final List<dynamic> forexList = data['data'];
|
||||||
@ -925,7 +978,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, dynamic>> listData =
|
final List<Map<String, dynamic>> listData =
|
||||||
@ -984,7 +1038,62 @@ class ApiService {
|
|||||||
|
|
||||||
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 Map<String, dynamic>.from(data['data']);
|
||||||
|
} catch (e) {
|
||||||
|
throw Exception('Error parsing response: $e');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw Exception('Failed to load department details');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<String, dynamic>> getForexTemplate() async {
|
||||||
|
final String apiUrldata =
|
||||||
|
'$apiUrl/api/getForexTemplate?template_name=forex';
|
||||||
|
|
||||||
|
final token = await getToken();
|
||||||
|
|
||||||
|
if (token == null) {
|
||||||
|
throw Exception('Token not found. Please log in.');
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(
|
||||||
|
Uri.parse(apiUrldata),
|
||||||
|
headers: {
|
||||||
|
'Authorization': 'Bearer $token',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
try {
|
||||||
|
final data = json.decode(response.body);
|
||||||
|
// print('findout the result');
|
||||||
|
// print(data.runtimeType);
|
||||||
|
print(data);
|
||||||
|
|
||||||
|
// if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
|
// throw Exception(
|
||||||
|
// "Invalid response format: 'data' field is missing or not a List");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// final List<Map<String, dynamic>> listData =
|
||||||
|
// List<Map<String, dynamic>>.from(data['data']);
|
||||||
|
//
|
||||||
|
// if (listData.isEmpty) {
|
||||||
|
// throw Exception("No department found with ID $id");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// return listData[0];
|
||||||
|
|
||||||
|
if (!data.containsKey('data') || data['data'] is! Map) {
|
||||||
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a Map",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Map<String, dynamic>.from(data['data']);
|
return Map<String, dynamic>.from(data['data']);
|
||||||
@ -997,7 +1106,9 @@ class ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<bool> showCancelConfirmationDialog(
|
Future<bool> showCancelConfirmationDialog(
|
||||||
BuildContext context, Color? layoutColor) async {
|
BuildContext context,
|
||||||
|
Color? layoutColor,
|
||||||
|
) async {
|
||||||
return await showDialog<bool>(
|
return await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
@ -1006,12 +1117,16 @@ class ApiService {
|
|||||||
title: Text(
|
title: Text(
|
||||||
'Cancel Confirmation',
|
'Cancel Confirmation',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 18, fontWeight: FontWeight.w500),
|
fontSize: 18,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
content: Text(
|
content: Text(
|
||||||
'Do you want to cancel?',
|
'Do you want to cancel?',
|
||||||
style: GoogleFonts.poppins(
|
style: GoogleFonts.poppins(
|
||||||
fontSize: 14.5, fontWeight: FontWeight.w500),
|
fontSize: 14.5,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
@ -1021,10 +1136,11 @@ class ApiService {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: layoutColor ?? Colors.grey, width: 2),
|
color: layoutColor ?? Colors.grey,
|
||||||
|
width: 2,
|
||||||
),
|
),
|
||||||
padding:
|
),
|
||||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).pop(false);
|
Navigator.of(context).pop(false);
|
||||||
@ -1032,7 +1148,8 @@ class ApiService {
|
|||||||
child: Text(
|
child: Text(
|
||||||
"Cancel",
|
"Cancel",
|
||||||
style: GoogleFonts.poppins(fontSize: 12),
|
style: GoogleFonts.poppins(fontSize: 12),
|
||||||
)),
|
),
|
||||||
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: layoutColor, // Keep original color
|
backgroundColor: layoutColor, // Keep original color
|
||||||
@ -1043,16 +1160,17 @@ class ApiService {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
side: BorderSide(
|
side: BorderSide(
|
||||||
color: layoutColor ?? Colors.grey, width: 1),
|
color: layoutColor ?? Colors.grey,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||||
),
|
),
|
||||||
onPressed: () => Navigator.of(context)
|
onPressed:
|
||||||
.pop(true), // Disable when in view mode
|
() => Navigator.of(
|
||||||
child: Text(
|
context,
|
||||||
"OK",
|
).pop(true), // Disable when in view mode
|
||||||
style: GoogleFonts.poppins(fontSize: 12),
|
child: Text("OK", style: GoogleFonts.poppins(fontSize: 12)),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -1087,7 +1205,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, dynamic>> listData =
|
final List<Map<String, dynamic>> listData =
|
||||||
@ -1132,7 +1251,8 @@ class ApiService {
|
|||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception(
|
throw Exception(
|
||||||
"Invalid response format: 'data' field is missing or not a List");
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, dynamic>> listData =
|
final List<Map<String, dynamic>> listData =
|
||||||
@ -1174,7 +1294,8 @@ class ApiService {
|
|||||||
print(data);
|
print(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",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
print('Single USer 1');
|
print('Single USer 1');
|
||||||
|
|
||||||
@ -1194,7 +1315,6 @@ class ApiService {
|
|||||||
Future<Map<String, dynamic>> getTravellerDetailsFind(int id) async {
|
Future<Map<String, dynamic>> getTravellerDetailsFind(int id) async {
|
||||||
final String apiUrldata = '$apiUrl/api/travellers/find?traveller_id=$id';
|
final String apiUrldata = '$apiUrl/api/travellers/find?traveller_id=$id';
|
||||||
|
|
||||||
|
|
||||||
//c
|
//c
|
||||||
final token = await getToken();
|
final token = await getToken();
|
||||||
|
|
||||||
@ -1215,7 +1335,9 @@ class ApiService {
|
|||||||
final data = json.decode(response.body);
|
final data = json.decode(response.body);
|
||||||
|
|
||||||
if (!data.containsKey('data') || data['data'] is! List) {
|
if (!data.containsKey('data') || data['data'] is! List) {
|
||||||
throw Exception("Invalid response format: 'data' field is missing or not a List");
|
throw Exception(
|
||||||
|
"Invalid response format: 'data' field is missing or not a List",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Map<String, dynamic>> listData =
|
final List<Map<String, dynamic>> listData =
|
||||||
@ -1233,5 +1355,4 @@ class ApiService {
|
|||||||
throw Exception('Failed to load Hotel details');
|
throw Exception('Failed to load Hotel details');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user